Theory CompoundCTypes

(*
 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
 * Copyright (c) 2022 Apple Inc. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 *)

theory CompoundCTypes
  imports
    Vanilla32
    Padding
    Lens
begin

lemma simple_type_dest: "¬aggregate t  n sz align align' d. t = TypDesc align' (TypScalar sz align d) n"
  apply (cases t)
  subgoal for x1 st n
    apply (cases st)
     apply auto
    done
  done

definition empty_typ_info :: "nat  typ_name  ('a,'b) typ_desc" where
  "empty_typ_info algn tn  TypDesc algn (TypAggregate []) tn"

(*
  More general type, may cause problems in some proofs as type inference
  extend_ti :: "('a,'b) typ_info ⇒ ('a,'b) typ_info ⇒ field_name ⇒ 'b ⇒ ('a,'b) typ_info" and
  extend_ti_struct :: "('a,'b) typ_info_struct ⇒ ('a,'b) typ_info ⇒ field_name ⇒ 'b ⇒ ('a,'b) typ_info_struct"

*)
primrec
  extend_ti :: "'a xtyp_info  'a xtyp_info  nat  field_name  'a field_desc  'a xtyp_info" and
  extend_ti_struct :: "'a xtyp_info_struct  'a xtyp_info  field_name  'a field_desc  'a xtyp_info_struct"
where
  et0: "extend_ti (TypDesc algn' st nm) t algn fn d  = TypDesc (max algn' (max algn (align_td t))) (extend_ti_struct st t fn d) nm"

| et1: "extend_ti_struct (TypScalar n sz algn) t fn d = TypAggregate [DTuple t fn d]"
| et2: "extend_ti_struct (TypAggregate ts) t fn d = TypAggregate (ts@[DTuple t fn d])"

lemma aggregate_empty_typ_info [simp]:
  "aggregate (empty_typ_info algn tn)"
  by (simp add: empty_typ_info_def)

lemma aggregate_extend_ti [simp]:
  "aggregate (extend_ti tag t algn f d)"
  apply(cases tag)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct, auto)
    done
  done

lemma typ_name_extend_ti [simp]: "typ_name (extend_ti T t algn fn d) = typ_name T"
  by (cases T) auto

definition update_desc :: "('a  'b)  ('b  'a  'a)  'b field_desc  'a field_desc" where
  "update_desc acc upd d  field_access = (field_access d)   acc,
                             field_update = λbs v. upd (field_update d bs (acc v)) v, field_sz = field_sz d "

lemma update_desc_id[simp]: "update_desc id (λx _. x) = id"
  by (simp add: update_desc_def fun_eq_iff)

term "map_td (λn algn. update_desc acc upd) (update_desc acc upd) t"


definition adjust_ti :: "'b xtyp_info  ('a  'b)  ('b  'a  'a)  'a xtyp_info" where
  "adjust_ti t acc upd  map_td (λn algn. update_desc acc upd) (update_desc acc upd) t"

lemma adjust_ti_adjust_ti:
  "adjust_ti (adjust_ti t g s) g' s' =
    adjust_ti t (g  g') (λv x. s' (s v (g' x)) x)"
  by (simp add: adjust_ti_def map_td_map update_desc_def[abs_def] comp_def)

lemma typ_desc_size_update_ti [simp]:
  "(size_td (adjust_ti t acc upd) = size_td t)"
  by (simp add: adjust_ti_def)

lemma export_tag_adjust_ti[rule_format]:
  "bs. fg_cons acc upd   wf_fd t 
    export_uinfo (adjust_ti t acc upd) = export_uinfo t"
  "bs. fg_cons acc upd  wf_fd_struct st 
    map_td_struct field_norm (λ_. ()) (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st) =
    map_td_struct field_norm (λ_. ()) st"
  "bs. fg_cons acc upd  wf_fd_list ts 
    map_td_list field_norm (λ_. ()) (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) ts) =
    map_td_list field_norm (λ_. ()) ts"
  "bs. fg_cons acc upd  wf_fd_tuple x 
    map_td_tuple field_norm (λ_. ()) (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) x) =
    map_td_tuple field_norm (λ_. ()) x"
  unfolding adjust_ti_def
  by (induct t and st and ts and x, all clarsimp simp: export_uinfo_def)
     (fastforce simp: update_desc_def field_norm_def fg_cons_def fd_cons_struct_def
                      fd_cons_access_update_def fd_cons_desc_def)


definition (in c_type) ti_typ_combine ::
  "'a itself  ('b  'a)  ('a  'b  'b)  nat  field_name  'b xtyp_info  'b xtyp_info"
  where
  "ti_typ_combine t_b acc upd algn fn tag 
     let ft = adjust_ti (typ_info_t TYPE('a)) acc upd
     in extend_ti tag ft algn fn field_access = xto_bytes o acc, field_update = upd o xfrom_bytes, field_sz = size_of TYPE('a)"

primrec
  padding_fields :: "('a,'b) typ_desc  field_name list" and
  padding_fields_struct :: "('a,'b) typ_struct  field_name list"
where
  pf0: "padding_fields (TypDesc algn st tn) = padding_fields_struct st"

| pf1: "padding_fields_struct (TypScalar n algn d) = []"
| pf2: "padding_fields_struct (TypAggregate xs) = filter (λx. hd x = CHR ''!'') (map dt_snd xs)"

primrec
  non_padding_fields :: "('a,'b) typ_desc  field_name list" and
  non_padding_fields_struct :: "('a,'b) typ_struct  field_name list"
where
  npf0: "non_padding_fields (TypDesc algn st tn) = non_padding_fields_struct st"

| npf1: "non_padding_fields_struct (TypScalar n algn d) = []"
| npf2: "non_padding_fields_struct (TypAggregate xs) = filter (λx. hd x  CHR ''!'') (map dt_snd xs)"

definition field_names_list :: "('a,'b) typ_desc  field_name list" where
  "field_names_list tag  non_padding_fields tag @ padding_fields tag"




definition ti_pad_combine :: "nat  'a xtyp_info  'a xtyp_info" where
  "ti_pad_combine n tag 
     let
       fn = foldl (@) ''!pad_'' (field_names_list tag);
       td = padding_desc n;
       nf = TypDesc 0 (TypScalar n 0 td) ''!pad_typ''
     in extend_ti tag nf 0 fn td"

lemma aggregate_ti_pad_combine [simp]:
  "aggregate (ti_pad_combine n tag)"
  by (simp add: ti_pad_combine_def Let_def)

definition (in c_type) ti_typ_pad_combine ::
  "'a itself  ('b  'a)  ('a  'b  'b)  nat  field_name  'b xtyp_info  'b xtyp_info"
  where
  "ti_typ_pad_combine t acc upd algn fn tag 
     let
       pad = padup (max (2 ^ algn) (align_of TYPE('a))) (size_td tag);
       ntag = if 0 < pad then ti_pad_combine pad tag else tag
     in
       ti_typ_combine t acc upd algn fn ntag"

definition "map_align f t = (case t of TypDesc algn st n  TypDesc (f algn) st n)"
lemma map_align_simp [simp]: "map_align f (TypDesc algn st n) = TypDesc (f algn) st n"
  by (simp add: map_align_def)


definition final_pad :: "nat  'a xtyp_info  'a xtyp_info" where
  "final_pad algn tag 
     let n = padup (2^(max algn (align_td tag))) (size_td tag)
     in map_align (max algn) (if 0 < n then ti_pad_combine n tag else tag)"

lemma field_names_list_empty_typ_info [simp]:
  "set (field_names_list (empty_typ_info algn tn)) = {}"
  by (simp add: empty_typ_info_def field_names_list_def)

lemma field_names_list_extend_ti [simp]:
  "set (field_names_list (extend_ti tag t algn fn d)) = set (field_names_list tag)  {fn}"
  unfolding field_names_list_def
  apply(cases tag)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct; simp)
    done
  done

lemma (in c_type) field_names_list_ti_typ_combine [simp]:
  "set (field_names_list (ti_typ_combine (t::'a itself) f f_upd algn fn tag))
     = set (field_names_list tag)  {fn}"
  by (clarsimp simp: ti_typ_combine_def Let_def)

lemma field_names_list_ti_pad_combine [simp]:
  "set (field_names_list (ti_pad_combine n tag))
     = set (field_names_list tag)  {foldl (@) ''!pad_'' (field_names_list tag)}"
  by (clarsimp simp: ti_pad_combine_def Let_def)

― ‹matches on padding›
lemma hd_string_hd_fold_eq [simp]:
  " s  []; hd s = CHR ''!''   hd (foldl (@) s xs) = CHR ''!''"
  by (induct xs arbitrary: s; clarsimp)

lemma field_names_list_ti_typ_pad_combine [simp]:
  "hd x  CHR ''!'' 
      x  set (field_names_list (ti_typ_pad_combine align t_b f_ab f_upd_ab fn tag))
          = (x  set (field_names_list tag)  {fn})"
  by (auto simp: ti_typ_pad_combine_def Let_def)

lemma wf_desc_empty_typ_info [simp]:
  "wf_desc (empty_typ_info algn tn)"
  by (simp add: empty_typ_info_def)

lemma wf_desc_extend_ti:
  " wf_desc tag; wf_desc t; f  set (field_names_list tag)  
      wf_desc (extend_ti tag t algn f d)"
  unfolding field_names_list_def
  apply(cases tag)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct; clarsimp)
    done
  done

lemma foldl_append_length:
  "length (foldl (@) s xs)  length s"
  apply(induct xs arbitrary: s, clarsimp)
  subgoal for  a list s
    apply(drule meta_spec [where x="s@a"])
    apply clarsimp
    done
  done

lemma foldl_append_nmem:
  "s  []  foldl (@) s xs  set xs"
  apply(induct xs arbitrary: s, clarsimp)
  subgoal for a list s
  apply(drule meta_spec [where x="s@a"])
    apply clarsimp
    by (metis add_le_same_cancel2 foldl_append_length le_zero_eq length_0_conv length_append)
  done

lemma wf_desc_ti_pad_combine:
  "wf_desc tag  wf_desc (ti_pad_combine n tag)"
  apply(clarsimp simp: ti_pad_combine_def Let_def)
  apply(erule wf_desc_extend_ti)
   apply simp
  apply(rule foldl_append_nmem, simp)
  done

lemma wf_desc_adjust_ti [simp]:
  "wf_desc (adjust_ti t f g) = wf_desc (t::'a xtyp_info)"
  by (simp add: adjust_ti_def wf_desc_map)

lemma (in wf_type) wf_desc_ti_typ_combine:
  " wf_desc tag; fn  set (field_names_list tag)  
    wf_desc (ti_typ_combine (t_b::'a itself) acc upd_ab algn fn tag)"
  by (fastforce simp: ti_typ_combine_def Let_def elim: wf_desc_extend_ti)

lemma (in wf_type) wf_desc_ti_typ_pad_combine:
  " wf_desc tag;  fn  set (field_names_list tag); hd fn  CHR ''!''  
   wf_desc (ti_typ_pad_combine (t_b::'a itself) acc upd algn fn tag)"
  unfolding ti_typ_pad_combine_def Let_def
  by (auto intro!: wf_desc_ti_typ_combine wf_desc_ti_pad_combine)

lemma wf_desc_map_align: "wf_desc tag  wf_desc (map_align f tag)"
  by (cases tag) (simp)

lemma wf_desc_final_pad:
  "wf_desc tag  wf_desc (final_pad algn tag)"
  by (auto simp: final_pad_def Let_def wf_desc_map_align wf_desc_ti_pad_combine)

lemma wf_size_desc_extend_ti:
  " wf_size_desc tag; wf_size_desc t   wf_size_desc (extend_ti tag t algn fn d)"
  apply(cases tag)
  subgoal for x1 typ_struct list
    apply(cases typ_struct, auto)
    done
  done

lemma wf_size_desc_ti_pad_combine:
  " wf_size_desc tag; 0 < n   wf_size_desc (ti_pad_combine n tag)"
  by (fastforce simp: ti_pad_combine_def Let_def elim: wf_size_desc_extend_ti)

lemma wf_size_desc_adjust_ti:
  "wf_size_desc (adjust_ti t f g) = wf_size_desc (t::'a xtyp_info)"
  by (simp add: adjust_ti_def wf_size_desc_map)

lemma (in wf_type) wf_size_desc_ti_typ_combine:
  "wf_size_desc tag  wf_size_desc (ti_typ_combine (t_b::'a itself) acc upd_ab algn fn tag)"
  by (fastforce simp: wf_size_desc_adjust_ti ti_typ_combine_def Let_def elim: wf_size_desc_extend_ti)

lemma (in wf_type) wf_size_desc_ti_typ_pad_combine:
  "wf_size_desc tag 
    wf_size_desc (ti_typ_pad_combine (t_b::'a itself) acc upd algn fn tag)"
  by (auto simp: ti_typ_pad_combine_def Let_def
           intro: wf_size_desc_ti_typ_combine
           elim: wf_size_desc_ti_pad_combine)

lemma (in wf_type) wf_size_desc_ti_typ_combine_empty [simp]:
  "wf_size_desc (ti_typ_combine (t_b::'a itself) acc upd algn fn (empty_typ_info algn' tn))"
  by (clarsimp simp: ti_typ_combine_def Let_def empty_typ_info_def wf_size_desc_adjust_ti)

lemma (in wf_type) wf_size_desc_ti_typ_pad_combine_empty [simp]:
  "wf_size_desc (ti_typ_pad_combine (t_b::'a itself) acc upd algn fn
      (empty_typ_info algn' tn))"
  by (clarsimp simp: ti_typ_pad_combine_def Let_def ti_typ_combine_def empty_typ_info_def
                     ti_pad_combine_def wf_size_desc_adjust_ti)

lemma wf_size_desc_msp_align:
  "wf_size_desc tag  wf_size_desc (map_align f tag)"
  by (cases tag) (simp add: wf_size_desc_def)

lemma wf_size_desc_final_pad:
  "wf_size_desc tag  wf_size_desc (final_pad algn tag)"
  by (fastforce simp: final_pad_def Let_def wf_size_desc_msp_align wf_size_desc_ti_pad_combine)

lemma wf_fdp_set_comp_simp [simp]:
  "wf_fdp {(a, n # b) |a b. (a, b)  tf_set t} = wf_fdp (tf_set t)"
  unfolding wf_fdp_def by fastforce

lemma lf_set_adjust_ti':
  "d fn. d  lf_set (map_td (λn algn. update_desc acc upd) (update_desc acc upd) t) fn 
      (y. lf_fd d=update_desc acc upd (lf_fd y)  lf_sz d=lf_sz y  lf_fn d=lf_fn y  y  lf_set t fn)"
  "d fn. d  lf_set_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st) fn 
      (y. lf_fd d=update_desc acc upd (lf_fd y)  lf_sz d=lf_sz y  lf_fn d=lf_fn y  y  lf_set_struct st fn)"
  "d fn. d  lf_set_list (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) ts) fn 
      (y. lf_fd d=update_desc acc upd (lf_fd y)  lf_sz d=lf_sz y  lf_fn d=lf_fn y  y  lf_set_list ts fn)"
  "d fn. d  lf_set_tuple (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) x) fn 
      (y. lf_fd d=update_desc acc upd (lf_fd y)  lf_sz d=lf_sz y  lf_fn d=lf_fn y  y  lf_set_tuple x fn)"
  unfolding update_desc_def
  by (induct t and st and ts and x) fastforce+

lemma lf_set_adjust_ti:
  " d  lf_set (adjust_ti t acc upd) fn; y. upd (acc y) y = y  
      (y. lf_fd d=update_desc acc upd (lf_fd y)  lf_sz d=lf_sz y  lf_fn d=lf_fn y  y  lf_set t fn)"
  by (simp add: lf_set_adjust_ti' adjust_ti_def)

lemma fd_cons_struct_id_simp [simp]:
  "fd_cons_struct (TypScalar n algn field_access = λv. id, field_update = λbs. id, field_sz = m)"
  by (auto simp: fd_cons_struct_def fd_cons_double_update_def
                 fd_cons_update_access_def fd_cons_access_update_def fd_cons_length_def
                 fd_cons_update_normalise_def fd_cons_desc_def)


lemma field_desc_adjust_ti:
  "fg_cons acc upd 
     field_desc (adjust_ti (t::'a xtyp_info) acc upd) =
     update_desc acc upd (field_desc t)"
  "fg_cons acc upd 
     field_desc_struct (map_td_struct (λn algn. update_desc  acc upd) (update_desc acc upd) st) =
     update_desc  acc upd (field_desc_struct st)"
  "fg_cons acc upd 
     field_desc_list (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) ts) =
     update_desc acc upd (field_desc_list ts)"
  "fg_cons acc upd 
     field_desc_tuple (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) x) =
     update_desc acc upd (field_desc_tuple x)"
  unfolding adjust_ti_def
     by (induct t and st and ts and x) (fastforce simp: fg_cons_def update_desc_def update_ti_t_struct_t)+

lemma update_ti_t_adjust_ti:
  "fg_cons acc upd  update_ti_t (adjust_ti t acc upd) bs v = upd (update_ti_t t bs (acc v)) v"
  using field_desc_adjust_ti(1) [of acc upd t]
  by (clarsimp simp: update_desc_def)

declare field_desc_def [simp del]

lemma (in c_type) aggregate_ti_typ_combine [simp]:
  "aggregate (ti_typ_combine (t_b::'a itself) acc upd algn fn tag)"
  by (simp add: ti_typ_combine_def Let_def)

lemma (in c_type) aggregate_ti_typ_pad_combine [simp]:
  "aggregate (ti_typ_pad_combine (t_b::'a itself) acc upd algn fn tag)"
  by (simp add: ti_typ_pad_combine_def Let_def)

lemma align_of_empty_typ_info [simp]:
  "align_td_wo_align (empty_typ_info algn tn) = 0"
  by (simp add: empty_typ_info_def)

lemma align_of_empty_typ_info' [simp]:
  "align_td (empty_typ_info algn tn) = algn"
  by (simp add: empty_typ_info_def)

lemma align_of_tag_list [simp]:
  "align_td_wo_align_list (xs @ [DTuple t fn d]) = max (align_td_wo_align_list xs) (align_td_wo_align t)"
  by (induct xs) auto

lemma align_of_tag_list' [simp]:
  "align_td_list (xs @ [DTuple t fn d]) = max (align_td_list xs) (align_td t)"
  by (induct xs) auto

lemma align_of_extend_ti [simp]:
  "aggregate ti  align_td_wo_align (extend_ti ti t algn fn d) = max (align_td_wo_align ti) (align_td_wo_align t)"
  apply (cases ti)
  subgoal for x1 typ_struct xs
    apply (cases typ_struct; clarsimp)
    done
  done

lemma align_of_extend_ti' [simp]:
  "aggregate ti  align_td (extend_ti ti t algn fn d) = max (align_td ti) (max algn (align_td t))"
  apply (cases ti)
  subgoal for x1 typ_struct xs
    apply (cases typ_struct; clarsimp)
    done
  done

lemma align_of_adjust_ti [simp]:
  "align_td_wo_align (adjust_ti t acc upd) = align_td_wo_align (t::'a xtyp_info)"
  by (simp add: adjust_ti_def)

lemma align_of_adjust_ti' [simp]:
  "align_td (adjust_ti t acc upd) = align_td (t::'a xtyp_info)"
  by (simp add: adjust_ti_def)

lemma (in c_type) align_of_ti_typ_combine [simp]:
  "aggregate ti 
     align_td_wo_align (ti_typ_combine (t::'a itself) acc upd algn fn ti) =
     max (align_td_wo_align ti) (align_td_wo_align (typ_info_t (TYPE('a))))"
  by (clarsimp simp: ti_typ_combine_def Let_def align_of_def)

lemma (in c_type) align_of_ti_typ_combine' [simp]:
  "aggregate ti 
     align_td (ti_typ_combine (t::'a itself) acc upd algn fn ti) =
     max (align_td ti) (max algn (align_td (typ_info_t TYPE('a))))"
  by (clarsimp simp: ti_typ_combine_def Let_def align_of_def)

lemma align_of_ti_pad_combine [simp]:
  "aggregate ti  align_td_wo_align (ti_pad_combine n ti) = (align_td_wo_align ti)"
  by (clarsimp simp: ti_pad_combine_def Let_def max_def)

lemma align_of_ti_pad_combine' [simp]:
  "aggregate ti  align_td (ti_pad_combine n ti) = (align_td ti)"
  by (clarsimp simp: ti_pad_combine_def Let_def max_def)

lemma max_2_exp: "max ((2::nat) ^ a) (2 ^ b) = 2 ^ (max a b)"
  by (simp add: max_def)

lemma align_td_wo_align_map_align: "align_td_wo_align (map_align f t) = align_td_wo_align t"
  by (cases t) simp

lemma align_td_wo_align_final_pad:
  "aggregate ti 
  align_td_wo_align (final_pad algn ti) = (align_td_wo_align ti)"
  by (simp add: final_pad_def Let_def  padup_def align_td_wo_align_map_align)

lemma align_td_map_align [simp]: "align_td (map_align f t) = f (align_td t)"
  by (cases t) simp

lemma align_of_final_pad:
  "aggregate ti 
  align_td (final_pad algn ti) = max algn (align_td ti)"
  by (simp add: final_pad_def Let_def  padup_def align_td_map_align )


lemma (in c_type) align_td_wo_align_ti_typ_pad_combine [simp]:
  "aggregate ti 
     align_td_wo_align (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti) =
     max (align_td_wo_align ti) (align_td_wo_align (typ_info_t TYPE('a)))"
  by (clarsimp simp: ti_typ_pad_combine_def Let_def)

lemma (in c_type) align_td_ti_typ_pad_combine [simp]:
  "aggregate ti 
     align_td (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti) =
     max (align_td ti) (max algn (align_td (typ_info_t TYPE('a))))"
  by (clarsimp simp: ti_typ_pad_combine_def Let_def)

definition fu_s_comm_set :: "(byte list  'a  'a) set  (byte list  'a  'a) set  bool"
  where
  "fu_s_comm_set X Y  x y. x  X  y  Y  (v bs bs'. x bs (y bs' v) = y bs' (x bs v))"

lemma fc_empty_ti [simp]:
  "fu_commutes (update_ti_t (empty_typ_info algn tn)) f"
  by (auto simp: fu_commutes_def empty_typ_info_def)

lemma fc_extend_ti:
  " fu_commutes (update_ti_t s) h; fu_commutes (update_ti_t t) h 
       fu_commutes (update_ti_t (extend_ti s t algn fn d)) h"
  apply(cases s)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct, auto simp: fu_commutes_def)
    done
  done

lemma fc_update_ti:
  " fu_commutes (update_ti_t ti) h; fg_cons acc upd;
     v bs bs'. upd bs (h bs' v) = h bs' (upd bs v); bs v. acc (h bs v) = acc v  
    fu_commutes (update_ti_t (adjust_ti t acc upd)) h"
  by (auto simp: fu_commutes_def update_ti_t_adjust_ti)

lemma (in c_type) fc_ti_typ_combine:
  " fu_commutes (update_ti_t ti) h; fg_cons acc upd;
     v bs bs'. upd bs (h bs' v) = h bs' (upd bs v); bs v. acc (h bs v) = acc v 
    fu_commutes (update_ti_t (ti_typ_combine (t::'a itself) acc upd algn fn ti)) h"
  apply(clarsimp simp: ti_typ_combine_def Let_def)
  apply(rule fc_extend_ti, assumption)
  apply(rule fc_update_ti; simp)
  done

lemma fc_ti_pad_combine:
  "fu_commutes (update_ti_t ti) f  fu_commutes (update_ti_t (ti_pad_combine n ti)) f"
  apply(clarsimp simp: ti_pad_combine_def Let_def)
  apply(rule fc_extend_ti, assumption)
  apply(auto simp: fu_commutes_def padding_desc_def)
  done

lemma (in c_type) fc_ti_typ_pad_combine:
  " fu_commutes (update_ti_t ti) h; fg_cons acc upd;
     v bs bs'. upd bs (h bs' v) = h bs' (upd bs v); bs v. acc (h bs v) = acc v 
    fu_commutes (update_ti_t (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti)) h"
  apply(clarsimp simp: ti_typ_pad_combine_def Let_def)
  apply(rule conjI; clarsimp)
   apply(rule fc_ti_typ_combine; assumption?)
   apply(erule fc_ti_pad_combine)
  apply(erule (3) fc_ti_typ_combine)
  done

definition fu_eq_mask :: "'a xtyp_info  ('a  'a)  bool" where
  "fu_eq_mask ti f 
     bs v v'. length bs = size_td ti  update_ti_t ti bs (f v) = update_ti_t ti bs (f v')"

lemma fu_eq_mask:
  " length bs = size_td ti; fu_eq_mask ti id   
      update_ti_t ti bs v = update_ti_t ti bs w"
 by (clarsimp simp: fu_eq_mask_def update_ti_t_def)

lemma fu_eq_mask_ti_pad_combine:
  " fu_eq_mask ti f; aggregate ti   fu_eq_mask (ti_pad_combine n ti) f"
  unfolding ti_pad_combine_def Let_def
  apply(cases ti)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct, auto simp: fu_eq_mask_def update_ti_list_t_def padding_desc_def)
    done
  done

lemma fu_eq_mask_map_align: "fu_eq_mask t f  fu_eq_mask (map_align g t) f"
  by (cases t) (auto simp add: fu_eq_mask_def)

lemma fu_eq_mask_final_pad:
  " fu_eq_mask ti f; aggregate ti   fu_eq_mask (final_pad algn ti) f"
  by(auto simp: final_pad_def Let_def fu_eq_mask_map_align fu_eq_mask_ti_pad_combine)

definition upd_local :: "('b  'a  'a)  bool" where
  "upd_local g  j k v v'. g k v = g k v'  g j v = g j v'"

lemma fg_cons_upd_local:
  "fg_cons f g  upd_local g"
  apply(clarsimp simp: fg_cons_def upd_local_def)
  subgoal for j k v v'
    apply(drule arg_cong [where f="g j"])
    apply simp
    done
  done

lemma (in mem_type) fu_eq_mask_ti_typ_combine:
  " fu_eq_mask ti (λv. (upd (acc undefined) (h v))); fg_cons acc upd;
      fu_commutes (update_ti_t ti) upd; aggregate ti  
      fu_eq_mask (ti_typ_combine (t::'a itself) acc upd algn fn ti) h"
  apply(frule fg_cons_upd_local)
  apply(clarsimp simp: ti_typ_combine_def Let_def)
  apply(cases ti)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct; clarsimp)
    subgoal for xs'
      apply(clarsimp simp: fu_eq_mask_def update_ti_t_adjust_ti)
      apply(clarsimp simp: update_ti_list_t_def size_of_def)
      apply(subst upd [where w="acc undefined"])
       apply(simp add: size_of_def)
      apply(subst upd [where w="acc undefined" and v="acc (h v')" for v'])
       apply(simp add: size_of_def)
      apply (smt (verit, ccfv_threshold) fu_commutes_def length_take min_ll upd_local_def)
      done
    done
  done

lemma (in mem_type) fu_eq_mask_ti_typ_pad_combine:
  " fu_eq_mask ti (λv. (upd (acc undefined) (h v))); fg_cons acc upd;
      fu_commutes (update_ti_t ti) upd; aggregate ti  
      fu_eq_mask (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti) h"
  by (fastforce simp: ti_typ_pad_combine_def Let_def
                intro: fu_eq_mask_ti_typ_combine fu_eq_mask_ti_pad_combine fc_ti_pad_combine)

lemma fu_eq_mask_empty_typ_info_g:
  "k. v. f v = k  fu_eq_mask t f"
  by (auto simp: fu_eq_mask_def)

lemma fu_eq_mask_empty_typ_info:
  "v. f v = undefined  fu_eq_mask t f"
 by (auto simp: fu_eq_mask_def)

lemma size_td_extend_ti:
  "aggregate s  size_td (extend_ti s t algn fn d) = size_td s + size_td t"
  apply (cases s) 
  subgoal for x1 typ_struct xs 
    apply (cases typ_struct; simp)
    done
  done

lemma size_td_ti_pad_combine:
  "aggregate ti  size_td (ti_pad_combine n ti) = n + size_td ti"
  unfolding ti_pad_combine_def Let_def by (simp add: size_td_extend_ti)

lemma size_td_map_align [simp]: "size_td (map_align f ti) = size_td ti"
  by (cases ti) auto

lemma align_of_dvd_size_of_final_pad [simp]:
  "aggregate ti  2^align_td (final_pad algn ti) dvd size_td (final_pad algn ti)"
  unfolding final_pad_def Let_def
  apply (cases ti)
  apply (auto simp: size_td_ti_pad_combine ac_simps padup_dvd power_le_dvd  intro: dvd_padup_add)
  done

lemma size_td_lt_ti_pad_combine:
  "aggregate t  size_td (ti_pad_combine n t) = size_td t + n"
  by (metis add.commute size_td_ti_pad_combine)

lemma (in c_type) size_td_lt_ti_typ_combine:
  "aggregate ti 
    size_td (ti_typ_combine (t::'a itself) f g algn fn ti) =
    size_td ti + size_td (typ_info_t TYPE('a))"
  by (clarsimp simp: ti_typ_combine_def Let_def size_td_extend_ti)

lemma (in c_type) size_td_lt_ti_typ_pad_combine:
  "aggregate ti  
      size_td (ti_typ_pad_combine (t::'a itself) f g algn fn ti) =
        (let k = size_td ti in
           k + size_td (typ_info_t TYPE('a)) + padup (2^(max algn (align_td (typ_info_t TYPE('a))))) k)"
  unfolding ti_typ_pad_combine_def Let_def
  by (auto simp: size_td_lt_ti_typ_combine size_td_ti_pad_combine align_of_def max_2_exp)

lemma size_td_lt_final_pad:
  "aggregate tag 
   size_td (final_pad align tag) = (let k=size_td tag in k + padup (2^(max align (align_td tag))) k)"
  by (auto simp: final_pad_def Let_def size_td_ti_pad_combine)

lemma size_td_empty_typ_info [simp]:
  "size_td (empty_typ_info algn tn) = 0"
  by (clarsimp simp: empty_typ_info_def)

lemma wf_lf_empty_typ_info [simp]:
  "wf_lf {}"
  by (auto simp: wf_lf_def empty_typ_info_def)

lemma lf_fn_disj_fn:
  "fn  set (field_names_list (TypDesc algn (TypAggregate xs) tn)) 
   lf_fn ` lf_set_list xs []  lf_fn ` lf_set t [fn] = {}"
  apply(induct xs arbitrary: fn t tn, clarsimp)
  subgoal for  a list fn t tn
  apply(cases a, clarsimp)
  apply(drule meta_spec [where x=fn])
  apply(drule meta_spec [where  x=t])
  apply(drule meta_spec [where  x=tn])
  apply(drule meta_mp, fastforce simp: field_names_list_def split: if_split_asm)
  apply(safe)
   apply(fastforce dest!: lf_set_fn simp: field_names_list_def prefix_def less_eq_list_def
                  split: if_split_asm)
    by force
  done


lemma wf_lf_extend_ti:
  " wf_lf (lf_set t []); wf_lf (lf_set ti []); wf_desc t; fn  set (field_names_list ti);
     ti_ind (lf_set ti []) (lf_set t [])  
   wf_lf (lf_set (extend_ti ti t algn fn d) [])"
  apply(cases ti)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct; clarsimp)
     apply(subst wf_lf_fn; simp)
    apply(subst wf_lf_list, erule lf_fn_disj_fn)
    apply(subst ti_ind_sym2)
    apply(subst ti_ind_fn)
    apply(subst ti_ind_sym2)
    apply clarsimp
    apply(subst wf_lf_fn; simp)
    done
  done

lemma wf_lf_ti_pad_combine:
  "wf_lf (lf_set ti [])  wf_lf (lf_set (ti_pad_combine n ti) [])"
  apply(clarsimp simp: ti_pad_combine_def Let_def padding_desc_def)
  apply(rule wf_lf_extend_ti)
      apply(clarsimp simp: wf_lf_def fd_cons_desc_def fd_cons_double_update_def
                           fd_cons_update_access_def fd_cons_access_update_def fd_cons_length_def)
     apply assumption
    apply(clarsimp)
   apply(rule foldl_append_nmem)
   apply clarsimp
  apply(clarsimp simp: ti_ind_def fu_commutes_def fa_fu_ind_def)
  done

lemma lf_set_map_align [simp]: "lf_set (map_align f ti) = lf_set ti"
  by (cases ti) auto

lemma wf_lf_final_pad:
  "wf_lf (lf_set ti [])  wf_lf (lf_set (final_pad algn ti) [])"
  by (auto simp: final_pad_def Let_def elim: wf_lf_ti_pad_combine)

lemma wf_lf_adjust_ti:
  " wf_lf (lf_set t []); v. g (f v) v = v;
      bs bs' v. g bs (g bs' v) = g bs v; bs v. f (g bs v) = bs 
       wf_lf (lf_set (adjust_ti t f g) [])"
  apply(clarsimp simp: wf_lf_def)
  apply(drule lf_set_adjust_ti; clarsimp)
  apply(rule conjI)
   apply(fastforce simp: fd_cons_desc_def fd_cons_double_update_def update_desc_def
                         fd_cons_update_access_def fd_cons_access_update_def fd_cons_length_def)
  apply(fastforce simp: fu_commutes_def update_desc_def fa_fu_ind_def dest!: lf_set_adjust_ti)
  done

lemma ti_ind_empty_typ_info [simp]:
  "ti_ind (lf_set (empty_typ_info algn tn) []) (lf_set (adjust_ti k f g) [])"
  by (clarsimp simp: ti_ind_def empty_typ_info_def)

lemma ti_ind_extend_ti:
  " ti_ind (lf_set t []) (lf_set (adjust_ti k acc upd) []);
      ti_ind (lf_set ti []) (lf_set (adjust_ti k acc upd) []) 
       ti_ind (lf_set (extend_ti ti t algn n d) []) (lf_set (adjust_ti k acc upd) [])"
  apply(cases ti)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct; clarsimp, subst ti_ind_fn, simp)
    done
  done

lemma ti_ind_ti_pad_combine:
  "ti_ind (lf_set ti []) (lf_set (adjust_ti k acc upd) []) 
      ti_ind (lf_set (ti_pad_combine n ti) []) (lf_set (adjust_ti k acc upd) [])"
  apply(clarsimp simp: ti_pad_combine_def Let_def padding_desc_def)
  apply(rule ti_ind_extend_ti)
   apply(clarsimp simp: ti_ind_def fu_commutes_def fa_fu_ind_def)
  apply assumption
  done

definition acc_ind :: "('a  'b)  'a field_desc set  bool" where
  "acc_ind acc X  x bs v. x  X  acc (field_update x bs v) = acc v"

definition fu_s_comm_k :: "'a leaf_desc set  ('b  'a  'a)  bool" where
  "fu_s_comm_k X upd  x. x  field_update ` lf_fd ` X  fu_commutes x upd"

definition upd_ind :: "'a leaf_desc set  ('b  'a  'a)  bool" where
  "upd_ind X upd  fu_s_comm_k X upd"

definition fa_ind :: "'a field_desc set  ('b  'a  'a)  bool" where
  "fa_ind X upd  x bs v. x  X  field_access x (upd bs v) = field_access x v"

lemma lf_fd_fn:
  "fn. lf_fd ` (lf_set (t::'a xtyp_info) fn) = lf_fd ` (lf_set t [])"
  "fn. lf_fd ` (lf_set_struct (st::'a xtyp_info_struct) fn) = lf_fd ` (lf_set_struct st [])"
  "fn. lf_fd ` (lf_set_list (ts::'a xtyp_info_tuple list) fn) = lf_fd ` (lf_set_list ts [])"
  "fn. lf_fd ` (lf_set_tuple (x::'a xtyp_info_tuple) fn) = lf_fd ` (lf_set_tuple x [])"
  by (induct t and st and ts and x, all clarsimp simp: image_Un) metis+

lemma lf_set_empty_typ_info [simp]:
  "lf_set (empty_typ_info algn tn) fn = {}"
  by (clarsimp simp: empty_typ_info_def)

lemma upd_ind_empty [simp]:
  "upd_ind {} upd"
  by (clarsimp simp: upd_ind_def fu_s_comm_k_def)

lemma upd_ind_extend_ti:
  " upd_ind (lf_set s []) upd; upd_ind (lf_set t []) upd  
      upd_ind (lf_set (extend_ti s t algn fn d) []) upd"
  apply (cases s)
  subgoal for x1 typ_struct xs
    apply (cases typ_struct)
    subgoal 
      apply (simp add:  upd_ind_def image_Un fu_s_comm_k_def )
      by (metis lf_fd_fn(1))
    subgoal 
      apply (simp add:  upd_ind_def image_Un fu_s_comm_k_def )
      by (metis lf_fd_fn(1))
    done
  done


lemma (in c_type) upd_ind_ti_typ_combine:
  " upd_ind (lf_set ti []) h; w u v. upd w (h u v) = h u (upd w v);
      w v. acc (h w v) = acc v; v. upd (acc v) v = v 
       upd_ind (lf_set (ti_typ_combine (t::'a itself) acc upd algn fn ti) []) h"
  apply(clarsimp simp: ti_typ_combine_def Let_def)
  apply(erule upd_ind_extend_ti)
  apply(clarsimp simp: upd_ind_def fu_s_comm_k_def)
  apply(drule lf_set_adjust_ti)
   apply clarsimp
  apply(clarsimp simp: update_desc_def fu_commutes_def )
  done

lemma upd_ind_ti_pad_combine:
  "upd_ind ((lf_set ti [])) upd  upd_ind ((lf_set (ti_pad_combine n ti) [])) upd"
  apply(clarsimp simp: ti_pad_combine_def Let_def padding_desc_def)
  apply(erule upd_ind_extend_ti)
  apply(auto simp: upd_ind_def fu_s_comm_k_def fu_commutes_def)
  done

lemma (in c_type) upd_ind_ti_typ_pad_combine:
  " upd_ind (lf_set ti []) h; w u v. upd w (h u v) = h u (upd w v);
      w v. acc (h w v) = acc v; v. upd (acc v) v = v 
       upd_ind (lf_set (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti) []) h"
  unfolding ti_typ_pad_combine_def Let_def
  by (fastforce intro!: upd_ind_ti_typ_combine upd_ind_ti_pad_combine)

lemma acc_ind_empty [simp]:
  "acc_ind acc {}"
  by (clarsimp simp: acc_ind_def)

lemma acc_ind_extend_ti:
  " acc_ind acc (lf_fd ` lf_set s []); acc_ind acc (lf_fd ` lf_set t [])  
      acc_ind acc (lf_fd ` lf_set (extend_ti s t algn fn d) [])"
  apply (cases s)
  subgoal for x1 typ_struct xs
    apply (cases typ_struct)
    subgoal 
      apply (simp add: acc_ind_def image_Un fu_s_comm_k_def )
      by (metis lf_fd_fn(1))
    subgoal 
      apply (simp add:  acc_ind_def image_Un fu_s_comm_k_def )
      by (metis lf_fd_fn(1))
    done
  done

lemma (in c_type) acc_ind_ti_typ_combine:
  " acc_ind h (lf_fd ` lf_set ti []); v w. h (upd w v) = h v;
      v. upd (acc v) v = v  
       acc_ind h (lf_fd ` lf_set (ti_typ_combine (t::'a itself) acc upd algn fn ti) [])"
  apply(clarsimp simp: ti_typ_combine_def Let_def)
  apply(erule acc_ind_extend_ti)
  apply(clarsimp simp: acc_ind_def)
  apply(drule lf_set_adjust_ti)
   apply clarsimp
  apply(clarsimp simp: update_desc_def)
  done

lemma acc_ind_ti_pad_combine:
  "acc_ind acc (lf_fd ` (lf_set t []))  acc_ind acc (lf_fd ` (lf_set (ti_pad_combine n t) []))"
  apply(clarsimp simp: ti_pad_combine_def Let_def padding_desc_def)
  apply(erule acc_ind_extend_ti)
  apply(auto simp: acc_ind_def)
  done

lemma (in c_type) acc_ind_ti_typ_pad_combine:
  " acc_ind h (lf_fd ` lf_set ti []); v w. h (upd w v) = h v; v. upd (acc v) v = v  
       acc_ind h (lf_fd ` lf_set (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti) [])"
  by (auto simp: ti_typ_pad_combine_def Let_def intro: acc_ind_ti_typ_combine acc_ind_ti_pad_combine)

lemma fa_ind_empty [simp]:
  "fa_ind {} upd"
  by (clarsimp simp: fa_ind_def)

lemma fa_ind_extend_ti:
  " fa_ind (lf_fd ` lf_set s []) upd; fa_ind (lf_fd ` lf_set t []) upd  
      fa_ind (lf_fd ` lf_set (extend_ti s t algn fn d) []) upd"
  apply (cases s)
  subgoal for x1 typ_struct xs
    apply (cases typ_struct)
    subgoal 
      apply (simp add: fa_ind_def image_Un fu_s_comm_k_def )
      by (metis lf_fd_fn(1))
    subgoal 
      apply (simp add:  fa_ind_def image_Un fu_s_comm_k_def )
      by (metis lf_fd_fn(1))
    done
  done
 
lemma (in c_type) fa_ind_ti_typ_combine:
  " fa_ind (lf_fd ` lf_set ti []) h; v w. acc (h w v) = acc v;
      v. upd (acc v) v = v   
       fa_ind (lf_fd ` lf_set (ti_typ_combine (t::'a itself) acc upd algn fn ti) []) h"
  apply(clarsimp simp: ti_typ_combine_def Let_def)
  apply(erule fa_ind_extend_ti)
  apply(clarsimp simp: fa_ind_def fu_s_comm_k_def)
  apply(drule lf_set_adjust_ti)
   apply clarsimp
  apply(clarsimp simp: update_desc_def fu_commutes_def)
  done

lemma fa_ind_ti_pad_combine:
  "fa_ind (lf_fd ` (lf_set ti [])) upd  fa_ind (lf_fd ` (lf_set (ti_pad_combine n ti) [])) upd"
  apply(clarsimp simp: ti_pad_combine_def Let_def padding_desc_def)
  apply(erule fa_ind_extend_ti)
  apply(auto simp: fa_ind_def)
  done

lemma (in c_type) fa_ind_ti_typ_pad_combine:
  " fa_ind (lf_fd ` lf_set ti []) h; v w. f (h w v) = f v;
      v. g (f v) v = v   
       fa_ind (lf_fd ` lf_set (ti_typ_pad_combine (t::'a itself) f g algn fn ti) []) h"
  by (auto simp: ti_typ_pad_combine_def Let_def intro: fa_ind_ti_typ_combine fa_ind_ti_pad_combine)

lemma (in wf_type) wf_lf_ti_typ_combine:
  " wf_lf (lf_set ti []); fn  set (field_names_list ti);
      v. upd (acc v) v = v; w u v. upd w (upd u v) = upd w v;
      w v. acc (upd w v) = w;
      upd_ind (lf_set ti []) upd; acc_ind acc (lf_fd ` lf_set ti []);
      fa_ind (lf_fd ` lf_set ti []) upd  
      wf_lf (lf_set (ti_typ_combine (t::'a itself) acc upd algn fn ti) [])"
  apply(clarsimp simp: ti_typ_combine_def Let_def)
  apply(rule wf_lf_extend_ti; simp?)
   apply(rule wf_lf_adjust_ti; simp)
  apply(clarsimp simp: ti_ind_def)
  apply(drule lf_set_adjust_ti, simp)
  apply(clarsimp simp: fu_commutes_def update_desc_def upd_ind_def acc_ind_def fu_s_comm_k_def
                       fa_fu_ind_def fa_ind_def)
  done

lemma (in wf_type) wf_lf_ti_typ_pad_combine:
  " wf_lf (lf_set ti []); fn  set (field_names_list ti); hd fn  CHR ''!'';
      v. upd (acc v) v = v; w u v. upd w (upd u v) = upd w v;
      w v. acc (upd w v) = w;
      upd_ind (lf_set ti []) upd; acc_ind acc (lf_fd ` lf_set ti []);
      fa_ind (lf_fd ` lf_set ti []) upd  
      wf_lf (lf_set (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti) [])"
  apply(clarsimp simp: ti_typ_pad_combine_def Let_def)
  apply (fastforce intro!: wf_lf_ti_typ_combine wf_lf_ti_pad_combine upd_ind_ti_pad_combine
                           acc_ind_ti_pad_combine fa_ind_ti_pad_combine)
  done

definition "upd_fa_ind X upd    upd_ind X upd  fa_ind (lf_fd ` X) upd"

lemma (in wf_type) wf_lf_ti_typ_pad_combine':
  " wf_lf (lf_set ti []); fn  set (field_names_list ti); hd fn  CHR ''!'';
      v. upd (acc v) v = v; w u v. upd w (upd u v) = upd w v;
      w v. acc (upd w v) = w;
      upd_fa_ind (lf_set ti []) upd; acc_ind acc (lf_fd ` lf_set ti [])
  
      wf_lf (lf_set (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti) [])"
  unfolding upd_fa_ind_def
  by (erule conjE) (rule wf_lf_ti_typ_pad_combine)


lemma (in c_type) upd_fa_ind_ti_typ_pad_combine:
" upd_fa_ind (lf_set ti []) h; w u v. upd w (h u v) = h u (upd w v);
      w v. acc (h w v) = acc v; v. upd (acc v) v = v 
       upd_fa_ind (lf_set (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti) []) h"
  unfolding upd_fa_ind_def
  by (auto intro: upd_ind_ti_typ_pad_combine fa_ind_ti_typ_pad_combine)

lemma upd_fa_ind_empty [simp]:
  "upd_fa_ind {} h"
  by (simp add: upd_fa_ind_def)

lemma wf_align_empty_typ_info: "wf_align (empty_typ_info algn tn)"
  by (simp add: wf_align_def empty_typ_info_def)

lemma wf_align_list: "wf_align t  wf_align_list fs   wf_align_list (fs @ [DTuple t f d])"
  by (induct fs) auto
lemma wf_align_struct: "wf_align t  wf_align_struct st  wf_align_struct (extend_ti_struct st t f d)"
  apply (cases st)
   apply simp
  apply (simp add: wf_align_list)
  done

lemma align_td_extend_ti: "align_td (extend_ti tag t algn f d) = max (align_td tag) (max algn (align_td t))"
  apply (cases tag)
  apply (simp)
  done

lemma align_td_struct_extend_ti: "aggregate_struct st 
  align_td_struct (extend_ti_struct st t f d) = max (align_td_struct st) (align_td t)"
  by (cases st) auto
lemma wf_align_extend_ti':
  assumes wf_t: "wf_align t"
  assumes agg: "aggregate tag"
  assumes wf_tag: "wf_align tag"
  shows "wf_align (extend_ti tag t algn f d)"
proof (cases tag)
  case (TypDesc algn' st n)
  with wf_tag agg obtain le: "align_td_wo_align_struct st  algn'"
   and le': "align_td_struct st  algn'"
   and wf_st: "wf_align_struct st"
   and agg_st: "aggregate_struct st" by auto
  from wf_align_struct [OF wf_t wf_st]
  have wf_st: "wf_align_struct (extend_ti_struct st t f d)" .
  from align_td_wo_align_le_align_td (2) [OF this]
  have "align_td_wo_align_struct (extend_ti_struct st t f d)  align_td_struct (extend_ti_struct st t f d)" .
  also from align_td_struct_extend_ti [OF agg_st]
  have " = max (align_td_struct st) (align_td t)" .
  finally
  have "align_td_wo_align_struct (extend_ti_struct st t f d)  max algn' (max algn (align_td t))"
    using le'
    by (metis (full_types) le_max_iff_disj max.orderE)
  moreover from align_td_struct_extend_ti [OF agg_st] le'
  have "align_td_struct (extend_ti_struct st t f d)  max algn' (max algn (align_td t))"
    by (metis max.cobounded2 max.mono )
  ultimately show ?thesis
    by (simp add: TypDesc wf_st)
qed

lemma (in mem_type) wf_align_extend_ti:
  assumes agg: "aggregate tag"
  assumes wf_tag: "wf_align tag"
  shows "wf_align (extend_ti tag (typ_info_t (TYPE('a))) algn f d)"
proof -
  have "wf_align (typ_info_t (TYPE('a)))" by (rule wf_align)
  from wf_align_extend_ti' [OF this agg wf_tag] show ?thesis .
qed

lemma wf_align_map_td [simp]:
"wf_align (map_td f g d) = wf_align d"
"wf_align_struct (map_td_struct f g ts) = wf_align_struct (ts)"
"wf_align_list (map_td_list f g fs) = wf_align_list fs"
"wf_align_tuple (map_td_tuple f g fd) = wf_align_tuple fd"
  by (induct d and ts and fs and fd) auto

lemma wf_align_adjust_ti[simp]: "wf_align (adjust_ti t acc upd) = wf_align t"
  by (simp add: adjust_ti_def)

lemma (in mem_type) wf_align_ti_typ_combine:
 "aggregate tag  wf_align tag  wf_align (ti_typ_combine (TYPE('a)) acc upd algn fn tag)"
  apply (simp add: ti_typ_combine_def Let_def)
  apply (rule wf_align_extend_ti')
    apply (simp add: wf_align)
   apply assumption
  apply assumption
  done

lemma wf_align_ti_pad_combine:
 "aggregate tag  wf_align tag  wf_align (ti_pad_combine n tag)"
  apply (simp add: ti_pad_combine_def Let_def)
  apply (rule wf_align_extend_ti')
    apply simp
   apply assumption
  apply assumption
  done

lemma (in mem_type) wf_align_ti_typ_pad_combine:
 "aggregate tag  wf_align tag  wf_align (ti_typ_pad_combine (TYPE('a)) acc upd algn fn tag)"
  by (simp add: ti_typ_pad_combine_def Let_def wf_align_ti_pad_combine wf_align_ti_typ_combine)

lemma wf_align_map_align:
  assumes wf_tag: "wf_align tag"
  assumes mono: "a. a  f a"
  shows "wf_align (map_align f tag)"
  using wf_tag mono
  apply (cases tag)
  using order_trans apply auto
  done

lemma wf_align_final_pad: "aggregate tag  wf_align tag  wf_align (final_pad algn tag)"
  by (auto simp add: final_pad_def Let_def max_2_exp wf_align_map_align wf_align_ti_pad_combine)

lemmas wf_align_simps =
  wf_align_empty_typ_info
  wf_align_ti_typ_pad_combine
  wf_align_ti_typ_combine
  wf_align_ti_pad_combine
  wf_align_final_pad

lemma align_field_empty_typ_info [simp]:
  "align_field (empty_typ_info algn tn)"
  by (clarsimp simp: empty_typ_info_def align_field_def)

lemma align_td_wo_align_field_lookup:
  "f m s n. field_lookup (t::('a,'b) typ_desc) f m = Some (s,n)  align_td_wo_align s  align_td_wo_align t"
  "f m s n. field_lookup_struct (st::('a,'b) typ_struct) f m = Some (s,n)  align_td_wo_align s  align_td_wo_align_struct st"
  "f m s n. field_lookup_list (ts::('a,'b) typ_tuple list) f m = Some (s,n)  align_td_wo_align s  align_td_wo_align_list ts"
  "f m s n. field_lookup_tuple (x::('a,'b) typ_tuple) f m = Some (s,n)  align_td_wo_align s  align_td_wo_align_tuple x"
  by (induct t and st and ts and x, all clarsimp)
     (fastforce simp: max_def split: option.splits)

lemma align_td_field_lookup[rule_format]:
  "f m s n. wf_align t  field_lookup (t::('a,'b) typ_desc) f m = Some (s,n)  align_td s  align_td t"
  "f m s n. wf_align_struct st  field_lookup_struct (st::('a,'b) typ_struct) f m = Some (s,n)  align_td s  align_td_struct st"
  "f m s n. wf_align_list ts  field_lookup_list (ts::('a,'b) typ_tuple list) f m = Some (s,n)  align_td s  align_td_list ts"
  "f m s n. wf_align_tuple x  field_lookup_tuple (x::('a,'b) typ_tuple) f m = Some (s,n)  align_td s  align_td_tuple x"
  apply (induct t and st and ts and x, all clarsimp)
    apply  (fastforce simp: max_def split: option.splits)+
  done

lemma (in mem_type) align_td_field_lookup_mem_type: "field_lookup (typ_info_t (TYPE('a))) f m = Some (s, n) 
  align_td s  align_td (typ_info_t (TYPE('a)))"
  apply (rule align_td_field_lookup(1))
   apply (rule wf_align)
  apply simp
  done

lemma align_field_extend_ti:
  " align_field s; align_field t; wf_align t;  2^(align_td t) dvd size_td s  
      align_field (extend_ti s t algn fn d)"
  apply(cases s, clarsimp)
  subgoal for x1 typ_struct xs
    apply(cases typ_struct, clarsimp)
     apply(clarsimp simp: align_field_def split: option.splits)
    apply(clarsimp simp: align_field_def)
    apply(subst (asm) field_lookup_list_append)
    apply(clarsimp split: if_split_asm option.splits)
    subgoal for x2 f s n
      apply(cases f, clarsimp)
      apply clarsimp
      apply(frule field_lookup_offset2)
      apply (meson align_td_field_lookup(1) dvd_diffD field_lookup_offset_le(1) power_le_dvd)
      done
    subgoal for x2 f s n
      by(cases f) auto       
    done
  done

lemma align_field_ti_pad_combine:
  "align_field ti  align_field (ti_pad_combine n ti)"
  apply(clarsimp simp: ti_pad_combine_def Let_def)
  apply(erule align_field_extend_ti)
   apply(clarsimp simp: align_field_def)
   apply clarsimp
  apply clarsimp
  done

lemma align_field_map_align [simp]: "align_field (map_align f t)  = align_field t"
  by (cases t) (auto simp add: align_field_def)

lemma align_field_final_pad:
  "align_field ti  align_field (final_pad algn ti)"
  apply(clarsimp simp: final_pad_def Let_def split: if_split_asm)
  apply(erule align_field_ti_pad_combine)
  done

lemma field_lookup_adjust_ti_None:
  "fn m s n. field_lookup (adjust_ti t acc upd) fn m = None 
      (field_lookup t fn m = None)"
  "fn m s n. field_lookup_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st)
        fn m = None 
        (field_lookup_struct st fn m = None)"
  "fn m s n. field_lookup_list (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) ts) fn m = None 
        (field_lookup_list ts fn m = None)"
  "fn m s n. field_lookup_tuple (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) x) fn m = None 
        (field_lookup_tuple x fn m = None)"
proof (induct t and st and ts and x)
  case (TypDesc nat typ_struct list)
  then show ?case by (clarsimp simp: adjust_ti_def split: option.splits)
next
  case (TypScalar nat1 nat2 a)
  then show ?case by auto
next
  case (TypAggregate list)
  then show ?case by auto
next
  case Nil_typ_desc
  then show ?case by auto
next
  case (Cons_typ_desc dt_tuple list)
  then show ?case
    apply (clarsimp simp: adjust_ti_def split: option.splits)
    apply (cases dt_tuple)
    apply clarsimp
    done
next
  case (DTuple_typ_desc typ_desc list b)
  then show ?case by (clarsimp simp: adjust_ti_def split: option.splits)
qed

lemma field_lookup_adjust_ti' [rule_format]:
  "fn m s n. field_lookup (adjust_ti t acc upd) fn m = Some (s,n) 
      (s'. field_lookup t fn m = Some (s',n)  align_td_wo_align s = align_td_wo_align s')"
  "fn m s n. field_lookup_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st)
        fn m = Some (s,n) 
        (s'. field_lookup_struct st fn m = Some (s',n)  align_td_wo_align s = align_td_wo_align s')"
  "fn m s n. field_lookup_list (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) ts) fn m = Some (s,n) 
        (s'. field_lookup_list ts fn m = Some (s',n)  align_td_wo_align s = align_td_wo_align s')"
  "fn m s n. field_lookup_tuple (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) x) fn m = Some (s,n) 
        (s'. field_lookup_tuple x fn m = Some (s',n)  align_td_wo_align s = align_td_wo_align s')"
proof (induct t and st and ts and x)
  case (TypDesc nat typ_struct list)
  then show ?case by (clarsimp simp: adjust_ti_def)
next
  case (TypScalar nat1 nat2 a)
  then show ?case by (clarsimp simp: adjust_ti_def)
next
  case (TypAggregate list)
  then show ?case by (clarsimp simp: adjust_ti_def)
next
  case Nil_typ_desc
  then show ?case by (clarsimp simp: adjust_ti_def)
next
  case (Cons_typ_desc dt_tuple list)
  then show ?case 
    apply (clarsimp simp: adjust_ti_def)
    apply(clarsimp split: option.splits)
     apply(rule conjI; clarsimp)
      apply(cases dt_tuple, clarsimp)
     apply(cases dt_tuple, clarsimp split: if_split_asm)
    subgoal for fn
      apply(drule spec [where x=fn])
      apply clarsimp
      apply(fold adjust_ti_def)
      apply(subst (asm) field_lookup_adjust_ti_None; simp)
      done
    apply fastforce
    done
next
  case (DTuple_typ_desc typ_desc list b)
  then show ?case by (clarsimp simp: adjust_ti_def)
qed

lemma field_lookup_adjust_ti''' [rule_format]:
  "fn m s n. field_lookup (adjust_ti t acc upd) fn m = Some (s,n) 
      (s'. field_lookup t fn m = Some (s',n)  align_td s = align_td s')"
  "fn m s n. field_lookup_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st)
        fn m = Some (s,n) 
        (s'. field_lookup_struct st fn m = Some (s',n)  align_td s = align_td s')"
  "fn m s n. field_lookup_list (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) ts) fn m = Some (s,n) 
        (s'. field_lookup_list ts fn m = Some (s',n)  align_td s = align_td s')"
  "fn m s n. field_lookup_tuple (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) x) fn m = Some (s,n) 
        (s'. field_lookup_tuple x fn m = Some (s',n)  align_td s = align_td s')"
proof(induct t and st and ts and x)
  case (TypDesc nat typ_struct list)
  then show ?case by (clarsimp simp: adjust_ti_def)
next
  case (TypScalar nat1 nat2 a)
  then show ?case by auto
next
  case (TypAggregate list)
  then show ?case by auto
next
  case Nil_typ_desc
  then show ?case by auto
next
  case (Cons_typ_desc dt_tuple list)
  then show ?case 
    apply(clarsimp simp: adjust_ti_def)
    apply(clarsimp split: option.splits)
     apply(rule conjI; clarsimp)
      apply(cases dt_tuple, clarsimp)
     apply(cases dt_tuple, clarsimp split: if_split_asm)
    subgoal for fn
      apply(drule spec [where x=fn])
      apply clarsimp
      apply(fold adjust_ti_def)
      apply(subst (asm) field_lookup_adjust_ti_None; simp)
      done
    apply fastforce
    done
next
  case (DTuple_typ_desc typ_desc list b)
  then show ?case  by(clarsimp simp: adjust_ti_def)
qed

lemma field_lookup_adjust_ti:
  " field_lookup (adjust_ti t acc upd) fn m = Some (s,n)  
      (s'. field_lookup t fn m = Some (s',n)  align_td_wo_align s = align_td_wo_align s')"
  by (rule field_lookup_adjust_ti')

lemma field_lookup_adjust_ti1:
  " field_lookup (adjust_ti t acc upd) fn m = Some (s,n)  
      (s'. field_lookup t fn m = Some (s',n)  align_td s = align_td s')"
  by (rule field_lookup_adjust_ti''')

lemma align_adjust_ti:
  "align_field ti  align_field (adjust_ti ti acc upd)"
  apply(clarsimp simp: align_field_def)
  apply(drule field_lookup_adjust_ti1)
  apply clarsimp
  done

lemma (in mem_type) align_field_ti_typ_combine:
  " align_field ti; 2 ^ align_td (typ_info_t TYPE('a)) dvd size_td ti  
   align_field (ti_typ_combine (t::'a itself) acc upd algn fn ti)"
  apply(clarsimp simp: ti_typ_combine_def Let_def)
  apply(rule align_field_extend_ti, assumption)
   apply(rule align_adjust_ti)
   apply(rule align_field)
   apply (simp add: wf_align)
  apply simp
  done

lemma (in mem_type) align_td_wo_align_type_info_t_le_align_td:
  "align_td_wo_align (typ_info_t TYPE('a))  align_td (typ_info_t TYPE('a))"
proof -
  have "wf_align (typ_info_t TYPE('a))" by (rule wf_align)
  then show ?thesis thm wf_align.wfal0 by (rule align_td_wo_align_le_align_td(1))
qed

lemma (in mem_type) align_field_ti_typ_pad_combine:
  "wf_align ti; align_field ti; aggregate ti 
   align_field (ti_typ_pad_combine (t::'a itself) acc upd algn fn ti)"

  unfolding ti_typ_pad_combine_def Let_def
  apply (rule align_field_ti_typ_combine)
  subgoal
    apply clarsimp
    apply (rule align_field_ti_pad_combine)
    apply assumption
    done
  apply clarsimp
  apply (rule conjI)
  subgoal
    apply (clarsimp simp add: align_of_def)
    apply (metis (no_types, lifting) align_td_wo_align_type_info_t_le_align_td dvd_padup_add max.cobounded2 max_2_exp
     power_le_dvd size_td_lt_ti_pad_combine zero_less_numeral zero_less_power)
    done
  apply (clarsimp simp add: align_of_def)
  by (simp add: max_2_exp padup_dvd power_le_dvd)

lemma npf_extend_ti [simp]:
  "non_padding_fields (extend_ti s t algn fn d) = non_padding_fields s @
      (if hd fn = CHR ''!'' then [] else [fn])"
  apply (cases s)
  subgoal for x1 typ_struct xs
    apply (cases typ_struct; simp)
    done
  done

lemma npf_ti_pad_combine [simp]:
  "non_padding_fields (ti_pad_combine n tag) = non_padding_fields tag"
  by (clarsimp simp: ti_pad_combine_def Let_def)

lemma (in c_type) npf_ti_typ_combine [simp]:
  "hd fn  CHR ''!'' 
   non_padding_fields (ti_typ_combine (t::'a itself) acc upd algn fn tag) = non_padding_fields tag @ [fn]"
  by (clarsimp simp: ti_typ_combine_def Let_def)

lemma (in c_type) npf_ti_typ_pad_combine [simp]:
  "hd fn  CHR ''!'' 
   non_padding_fields (ti_typ_pad_combine (t::'a itself) acc upd algn fn tag) = non_padding_fields tag @ [fn]"
  by (clarsimp simp: ti_typ_pad_combine_def Let_def)

lemma non_padding_fields_map_align [simp]:
 "non_padding_fields (map_align f t) = non_padding_fields t"
  by (cases t) simp

lemma npf_final_pad [simp]:
  "non_padding_fields (final_pad algn tag) = non_padding_fields tag"
  by (clarsimp simp: final_pad_def Let_def)

lemma npf_empty_typ_info [simp]:
  "non_padding_fields (empty_typ_info algn tn) = []"
  by (clarsimp simp: empty_typ_info_def)

definition field_fd' :: "'a xtyp_info  qualified_field_name  'a field_desc" where
  "field_fd' t f  case field_lookup t f 0 of None  None | Some x  Some (field_desc (fst x))"

lemma padup_zero [simp]:
  "padup n 0 = 0"
  by (clarsimp simp: padup_def)

lemma padup_same [simp]:
  "padup n n = 0"
  by (clarsimp simp: padup_def)

lemmas size_td_simps_0 = size_td_lt_final_pad size_td_lt_ti_typ_pad_combine

lemmas size_td_simps_1 = size_td_simps_0
                         aggregate_ti_typ_pad_combine aggregate_empty_typ_info

lemmas size_td_simps_2 = padup_def align_of_final_pad align_of_def

lemmas size_td_simps = size_td_simps_1 size_td_simps_2

lemmas size_td_simps_3 = size_td_simps_0 size_td_simps_2


lemma fu_commutes_sym: "fu_commutes x y = fu_commutes y x"
  by (auto simp add: fu_commutes_def)

(*fixme: remove unused? *)
lemma wf_lf_insert_recursion:
  assumes wf_D:  "wf_lf D"
  assumes cons_x: "fd_cons_desc (lf_fd x) (lf_sz x)"
  assumes comm_D: "y. y  D  fu_commutes (field_update (lf_fd x)) (field_update (lf_fd y)) 
            fa_fu_ind (lf_fd x) (lf_fd y) (lf_sz y) (lf_sz x) 
            fa_fu_ind (lf_fd y) (lf_fd x) (lf_sz x) (lf_sz y)"
  shows "wf_lf (insert x D)"
proof -
  have comm_x_D:
   "fu_commutes (field_update (lf_fd x')) (field_update (lf_fd y))" and
   "fa_fu_ind (lf_fd x') (lf_fd y) (lf_sz y) (lf_sz x')"
    if x'_in: "x'  insert x D" and y_in: "y  insert x D" and neq: "lf_fn y  lf_fn x'"
    for x' and y
  proof - (*(induct "x' = x")*)
    show "fu_commutes (field_update (lf_fd x')) (field_update (lf_fd y))"
      proof (cases "x' = x")
        case True
        from True y_in neq comm_D x'_in show ?thesis
          by auto
      next
        case False
        note neq_x'_x = this
        with x'_in have x'_D: "x'  D"
          by auto
        from comm_D [OF this] have "fu_commutes (field_update (lf_fd x)) (field_update (lf_fd x'))"
          by auto
        with fu_commutes_sym have comm_x'_x: "fu_commutes (field_update (lf_fd x')) (field_update (lf_fd x))"
          by auto
        from neq have neq': "y  x'"
          by auto
        show ?thesis
        proof (cases "y = x")
          case True
          with comm_x'_x show ?thesis by simp
        next
          case False
          from False y_in have y_D: "y  D" by simp
          with x'_D neq wf_D
          show ?thesis
            by (auto simp add: wf_lf_def)
        qed
      qed
    next
      show "fa_fu_ind (lf_fd x') (lf_fd y) (lf_sz y) (lf_sz x')"
      proof (cases "x' = x")
        case True
        from True y_in neq comm_D x'_in show ?thesis
          by auto
      next
        case False
        note neq_x'_x = this
        with x'_in have x'_D: "x'  D"
          by auto
        from comm_D [OF this] have "fa_fu_ind (lf_fd x) (lf_fd x') (lf_sz x') (lf_sz x)" and
            fa_fu_x'_x: "fa_fu_ind (lf_fd x') (lf_fd x) (lf_sz x) (lf_sz x')" by auto
        from neq have neq': "y  x'"
          by auto
        show ?thesis
        proof (cases "y = x")
          case True
          with fa_fu_x'_x show ?thesis by simp
        next
          case False
          from False y_in have y_D: "y  D" by simp
          with x'_D neq wf_D
          show ?thesis
            by (auto simp add: wf_lf_def)
        qed
      qed
    qed
    with cons_x wf_D
    show ?thesis
      by (auto simp add: wf_lf_def)
qed


(*fixme: remove unused? *)
lemma wf_lf_insert_recursion':
  assumes cons_x: "fd_cons_desc (lf_fd x) (lf_sz x)"
  assumes comm_D: "y. y  D  fu_commutes (field_update (lf_fd x)) (field_update (lf_fd y)) 
            fa_fu_ind (lf_fd x) (lf_fd y) (lf_sz y) (lf_sz x) 
            fa_fu_ind (lf_fd y) (lf_fd x) (lf_sz x) (lf_sz y)"
  assumes wf_D:  "wf_lf D"
  shows "wf_lf (insert x D)"
  using wf_D cons_x comm_D
  by (rule wf_lf_insert_recursion)

(*fixme: remove unused? *)
lemma wf_lf_insert_recursion'':
  assumes wf_D:  "wf_lf D"
  assumes cons_x: "fd_cons_desc (lf_fd x) (lf_sz x)"
  assumes comm_D: "y. y  D  lf_fn y  lf_fn x  fu_commutes (field_update (lf_fd x)) (field_update (lf_fd y)) 
            fa_fu_ind (lf_fd x) (lf_fd y) (lf_sz y) (lf_sz x) 
            fa_fu_ind (lf_fd y) (lf_fd x) (lf_sz x) (lf_sz y)"
  shows "wf_lf (insert x D)"
proof -
  have comm_x_D:
   "fu_commutes (field_update (lf_fd x')) (field_update (lf_fd y))" and
   "fa_fu_ind (lf_fd x') (lf_fd y) (lf_sz y) (lf_sz x')"
    if x'_in: "x'  insert x D" and y_in: "y  insert x D" and neq: "lf_fn y  lf_fn x'"
    for x' and y
  proof - (*(induct "x' = x")*)
    show "fu_commutes (field_update (lf_fd x')) (field_update (lf_fd y))"
      proof (cases "x' = x")
        case True
        from True y_in neq comm_D x'_in show ?thesis
          by auto
      next
        case False
        note neq_x'_x = this
        with x'_in have x'_D: "x'  D"
          by auto
        from neq have neq': "y  x'"
          by auto
        show ?thesis
        proof (cases "y = x")
          case True
          with neq neq_x'_x neq'
          have "lf_fn x'  lf_fn x" by simp
          from comm_D [OF x'_D this]  have "fu_commutes (field_update (lf_fd x)) (field_update (lf_fd x'))"
            by auto
          with fu_commutes_sym have comm_x'_x: "fu_commutes (field_update (lf_fd x')) (field_update (lf_fd x))"
            by auto
          from True comm_x'_x show ?thesis by simp
        next
          case False
          from False y_in have y_D: "y  D" by simp
          with x'_D neq wf_D
          show ?thesis
            by (auto simp add: wf_lf_def)
        qed
      qed
    next
      show "fa_fu_ind (lf_fd x') (lf_fd y) (lf_sz y) (lf_sz x')"
      proof (cases "x' = x")
        case True
        from True y_in neq comm_D x'_in show ?thesis
          by auto
      next
        case False
        note neq_x'_x = this
        with x'_in have x'_D: "x'  D"
          by auto
        from neq have neq': "y  x'"
          by auto
        show ?thesis
        proof (cases "y = x")
          case True
          with neq neq_x'_x neq'
          have "lf_fn x'  lf_fn x" by simp
          from comm_D [OF x'_D this] have "fa_fu_ind (lf_fd x) (lf_fd x') (lf_sz x') (lf_sz x)" and
            fa_fu_x'_x: "fa_fu_ind (lf_fd x') (lf_fd x) (lf_sz x) (lf_sz x')" by auto
          from True fa_fu_x'_x show ?thesis by simp
        next
          case False
          from False y_in have y_D: "y  D" by simp
          with x'_D neq wf_D
          show ?thesis
            by (auto simp add: wf_lf_def)
        qed
      qed
    qed
    with cons_x wf_D
    show ?thesis
      by (auto simp add: wf_lf_def)
  qed


lemma wf_field_desc_empty [simp]:
"wf_field_desc field_access = λv bs. [], field_update = λbs. id, field_sz = 0"
  by (unfold_locales) (auto simp add: padding_base.eq_padding_def padding_base.eq_upto_padding_def)


lemma field_desc_independent_subset:
  "D  E  field_desc_independent acc upd E  field_desc_independent acc upd D"
  by (auto simp add: field_desc_independent_def)

lemma field_desc_independent_union_iff:
 "field_desc_independent acc upd (D  E) =
   (field_desc_independent acc upd D  field_desc_independent acc upd E)"
  by (auto simp add: field_desc_independent_def)

lemma field_desc_independent_unionI:
 "field_desc_independent acc upd D  field_desc_independent acc upd E 
  field_desc_independent acc upd (D  E)"
  by (simp add: field_desc_independent_union_iff)

lemma field_desc_independent_unionD1:
 "field_desc_independent acc upd (D  E) 
   field_desc_independent acc upd D"
  by (simp add: field_desc_independent_union_iff)

lemma field_desc_independent_unionD2:
 "field_desc_independent acc upd (D  E) 
   field_desc_independent acc upd E"
  by (simp add: field_desc_independent_union_iff)

lemma field_desc_independent_insert_iff:
  "field_desc_independent acc upd (insert d D) =
    (field_desc_independent acc upd {d}  field_desc_independent acc upd D)"
  apply (subst insert_is_Un)
  apply (simp only: field_desc_independent_union_iff)
  done

lemma field_desc_independent_insertI:
  "field_desc_independent acc upd {d}  field_desc_independent acc upd D 
   field_desc_independent acc upd (insert d D)"
  apply (subst insert_is_Un)
  apply (simp only: field_desc_independent_union_iff)
  done

lemma field_desc_independent_insertD1:
  assumes ins: "field_desc_independent acc upd (insert d D)"
  shows "field_desc_independent acc upd {d}"
proof -
  from ins have "field_desc_independent acc upd ({d}  D)"
    by (simp)
  from field_desc_independent_unionD1 [OF this]
  show ?thesis .
qed

lemma field_desc_independent_insertD2:
  assumes ins: "field_desc_independent acc upd (insert d D)"
  shows "field_desc_independent acc upd D"
proof -
  from ins have "field_desc_independent acc upd ({d}  D)"
    by (simp)
  from field_desc_independent_unionD2 [OF this]
  show ?thesis .
qed



lemma field_descs_independent_append_first: "field_descs_independent (xs @ ys)  field_descs_independent xs"
  by (induct xs arbitrary: ys) (auto intro: field_desc_independent_subset)

lemma field_descs_independent_append_second: "field_descs_independent (xs @ ys)  field_descs_independent ys"
  by (induct xs arbitrary: ys) (auto intro: field_desc_independent_subset)

lemma field_descs_independent_append_first_ind:
 "field_descs_independent (xs @ ys)  x  set xs 
       field_desc_independent (field_access x) (field_update x) (set ys)"
by (induct xs arbitrary: ys) (auto simp add: field_desc_independent_union_iff)

lemma field_descs_independent_appendI1:
 "field_descs_independent xs  field_descs_independent ys 
 (x  set xs. field_desc_independent (field_access x) (field_update x) (set ys)) 
 field_descs_independent (xs @ ys)"
  by (induct xs arbitrary: ys) (auto simp add: field_desc_independent_union_iff)


lemma field_desc_independent_symmetric:
"(x  X. field_desc_independent (field_access x) (field_update x) Y) 
 (y  Y. field_desc_independent (field_access y) (field_update y) X)"
  by (simp add: field_desc_independent_def fu_commutes_def)

lemma field_desc_independent_symmetric_singleton:
"field_desc_independent (field_access x) (field_update x) Y  y  Y
 field_desc_independent (field_access y) (field_update y) {x}"
  using field_desc_independent_symmetric by blast

lemma field_descs_independent_appendI2:
  assumes ind_xs: "field_descs_independent xs"
  assumes ind_ys: "field_descs_independent ys"
  assumes ind_xs_ys: "y  set ys. field_desc_independent (field_access y) (field_update y) (set xs)"
  shows "field_descs_independent (xs @ ys)"
  using field_desc_independent_symmetric [OF ind_xs_ys] ind_xs ind_ys
  by (auto intro: field_descs_independent_appendI1)


lemma field_desc_indepenent_empty [simp]:
  "field_desc_independent (field_access d) (field_update d) {}" by (simp add: field_desc_independent_def)



lemma field_update_apply_field_updates_commute:
  fixes d::"'a field_desc"
  fixes ds::"'a field_desc list"
assumes ind_d:"field_desc_independent (field_access d) (field_update d) (set ds)"
assumes ind_ds: "field_descs_independent ds"
shows "field_update d bs (fst (apply_field_updates ds bs' s)) =
  fst (apply_field_updates ds bs' (field_update d bs s))"
using ind_d ind_ds
proof (induct ds arbitrary: d bs bs' s)
case Nil
then show ?case by simp
next
  case (Cons d' ds')
  from Cons.prems obtain
    ind_d1:  "field_desc_independent (field_access d) (field_update d) (insert d' (set ds'))" and
    ind_d': "field_desc_independent (field_access d') (field_update d') (set ds')" and
    ind_d: "field_desc_independent (field_access d) (field_update d) (set ds')" and
    ind_ds': "field_descs_independent ds'"
    by (auto intro: field_desc_independent_subset)

  from ind_d1 interpret fi: field_desc_independent "field_access d" "field_update d" "insert d' (set ds')" .
  from fi.fu_commutes [of d']
  have "fu_commutes (field_update d) (field_update d')" by simp
  then
  have d_d'_com: "field_update d bs (field_update d' bs' s) = (field_update d' bs' (field_update d bs s))"
    by (auto simp add: fu_commutes_def)

  from Cons.prems obtain
    ind_d': "field_desc_independent (field_access d') (field_update d') (set ds')" and
    ind_d: "field_desc_independent (field_access d) (field_update d) (set ds')" and
    ind_ds': "field_descs_independent ds'"
    by (auto intro: field_desc_independent_subset)

  note hyp = Cons.hyps [OF ind_d ind_ds']

  show ?case by (simp add: hyp d_d'_com)
qed

lemma (in wf_field_desc) is_padding_byte_acc_upd_compose:
  assumes acc_upd: "v s. acc (upd v s) = v"
  shows "padding_base.is_padding_byte (field_access d  acc)
     (λbs v. upd (field_update d bs (acc v)) v) (field_sz d) i =
     is_padding_byte i "
  apply (simp add: is_padding_byte_def padding_base.is_padding_byte_def)
  by (metis acc_upd)

lemma (in wf_field_desc) is_value_byte_acc_upd_compose:
  assumes acc_upd: "v s. acc (upd v s) = v"
  shows "padding_base.is_value_byte (field_access d  acc)
     (λbs v. upd (field_update d bs (acc v)) v) (field_sz d) i =
     is_value_byte i "
  apply (simp add: is_value_byte_def padding_base.is_value_byte_def)
  by (metis acc_upd)

lemma (in wf_field_desc) wf_field_desc_update_desc:
  assumes double_update_upd: "v w s. upd v (upd w s) = upd v s"
  assumes acc_upd: "v s. acc (upd v s) = v"
  assumes upd_acc: "s. upd (acc s) s = s"
  shows "wf_field_desc (update_desc acc upd d)" (is "wf_field_desc ?upd")
proof (unfold_locales)
  fix i
  assume i_bound: "i < field_sz (update_desc acc upd d)"
  show "padding_base.is_padding_byte (field_access (update_desc acc upd d))
          (field_update (update_desc acc upd d))
          (field_sz (update_desc acc upd d)) i 
         padding_base.is_value_byte (field_access (update_desc acc upd d))
          (field_update (update_desc acc upd d))
          (field_sz (update_desc acc upd d)) i"
    using complement i_bound
    by (simp add: update_desc_def is_padding_byte_acc_upd_compose [of acc upd, OF acc_upd]
        is_value_byte_acc_upd_compose [of acc upd, OF acc_upd])
next
  fix bs bs' s
  show "field_update ?upd bs (field_update ?upd bs' s) = field_update ?upd bs s"
    by (simp add: update_desc_def double_update double_update_upd acc_upd)
next
  fix bs s bs' s'
  show "field_access ?upd (field_update ?upd bs s) bs' = field_access ?upd (field_update ?upd bs s') bs'"
    by (simp add: update_desc_def access_update acc_upd)
next
  fix s bs
  show "field_update ?upd (field_access ?upd s bs) s = s"
    by (simp add: update_desc_def update_access upd_acc)
next
  fix s bs
  show "(field_access ?upd s (take (field_sz ?upd) bs)) = field_access ?upd s bs"
    by (simp add: update_desc_def access_size)
next
  fix s bs
  show "length (field_access ?upd s bs) = field_sz ?upd"
    by (simp add: update_desc_def access_result_size)
next
  fix bs
  show "field_update ?upd (take (field_sz ?upd) bs) = field_update ?upd bs"
    by (simp add: update_desc_def update_size)
qed



lemma toplevel_field_descs_subset:
  fixes t::"'a xtyp_info" and
   st::"'a xtyp_info_struct" and
   fs::"'a xtyp_info_tuple list" and
   f::"'a xtyp_info_tuple"
 shows
  "set (toplevel_field_descs t)  set (field_descs t)"
  "set (toplevel_field_descs_struct st)  set (field_descs_struct st)"
  "set (toplevel_field_descs_list fs)  set (field_descs_list fs)"
  "set (toplevel_field_descs_tuple f)  set (field_descs_tuple f)"
  by (induct t and st and fs and f) auto


lemma
  fixes t::"'a xtyp_info" and
   st::"'a xtyp_info_struct" and
   fs::"'a xtyp_info_tuple list" and
   f::"'a xtyp_info_tuple"
 shows
 " lf_fd ` lf_set t xs  set (field_descs t)"
  " lf_fd ` lf_set_struct st xs  set (field_descs_struct st)"
  " lf_fd ` lf_set_list fs xs  set (field_descs_list fs)"
  " lf_fd ` lf_set_tuple f xs  set (field_descs_tuple f)"
     apply (induction t and st and fs and f arbitrary: xs) apply auto
  oops (* fixme: checkout why arbitrary: xs does not work here *)



lemma lf_set_subset_field_descs:
  fixes t::"'a xtyp_info" and
   st::"'a xtyp_info_struct" and
   fs::"'a xtyp_info_tuple list" and
   f::"'a xtyp_info_tuple"
 shows
 "xs. lf_fd ` lf_set t xs  set (field_descs t)"
 "xs. lf_fd ` lf_set_struct st xs  set (field_descs_struct st)"
 "xs. lf_fd ` lf_set_list fs xs  set (field_descs_list fs)"
 "xs. lf_fd ` lf_set_tuple f xs  set (field_descs_tuple f)"
  by (induction t and st and fs and f) (auto simp add: image_subset_iff)


lemma wf_field_descs_empty_typ_info [simp]: "wf_field_descs (set (field_descs (empty_typ_info algn t)))"
  by (simp add: empty_typ_info_def wf_field_descs_def)


lemma field_descs_map:
  "field_descs (map_td (λ_ _. update_desc acc upd) (update_desc acc upd) t) =
     map (update_desc acc upd) (field_descs t)"
  "field_descs_struct (map_td_struct (λ_ _. update_desc acc upd) (update_desc acc upd) st) =
     map (update_desc acc upd) (field_descs_struct st)"
  "field_descs_list (map_td_list (λ_ _. update_desc acc upd) (update_desc acc upd) fs) =
     map (update_desc acc upd) (field_descs_list fs)"
  "field_descs_tuple (map_td_tuple (λ_ _. update_desc acc upd) (update_desc acc upd) f) =
     map (update_desc acc upd) (field_descs_tuple f)"
  by (induct t and st and fs and f) auto


lemma component_update_access:
  assumes wf:"wf_field_descs (set (field_descs t))"
  shows "field_update (component_desc t)
         (field_access (component_desc t) s bs) s = s"
proof (cases t)
  case (TypDesc algn st n)
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from TypDesc TypScalar have "d  set (field_descs t)" by simp
    with wf have "wf_field_desc d" by (simp add: wf_field_descs_def)
    then interpret wf_d: wf_field_desc d .
    from TypDesc TypScalar wf_d.update_access show ?thesis
      by simp
  next
    case (TypAggregate fs)
    from wf have "wf_field_descs (set (field_descs_list fs))" by (simp add: TypDesc TypAggregate)
    then
    have "fst (apply_field_updates (map dt_trd fs)
            (concat (split_map (component_access_tuple s) fs bs)) s) = s"
    proof (induct fs arbitrary: s bs)
      case Nil
      then show ?case by simp
    next
      case (Cons f fs')

      obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

      from Cons f obtain
        wf_d: "wf_field_desc d" and
        wf_ft: "wf_field_descs (set (field_descs ft))" and
        wf_fs': "wf_field_descs (set (field_descs_list fs'))" by auto


      from wf_d interpret wf_d: wf_field_desc d .
      from Cons.hyps [OF wf_fs']
      have "fst (apply_field_updates (map dt_trd fs')
             (concat (split_map (component_access_tuple s) fs' (drop (field_sz d) bs))) s) = s" .
      then
      show ?case
        by (simp add: Cons f wf_d.access_result_size wf_d.update_access_append)
    qed
    with TypDesc TypAggregate show ?thesis by simp
  qed
qed

lemma toplevel_field_descs_tuple_dt_trd: "toplevel_field_descs_tuple t = [dt_trd t]"
  by (cases t) simp
lemma toplevel_field_descs_list_map: "toplevel_field_descs_list fs = map dt_trd fs"
  by (induct fs) (auto simp add: toplevel_field_descs_tuple_dt_trd)

lemma component_double_update:
  assumes wf:"wf_field_descs (set (field_descs t))"
  assumes ind: "field_descs_independent (toplevel_field_descs t)"
  shows"field_update (component_desc t) bs (field_update (component_desc t) bs' s) =
        field_update (component_desc t) bs s"
proof (cases t)
  case (TypDesc algn st n)
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from TypDesc TypScalar have "d  set (field_descs t)" by simp
    with wf have "wf_field_desc d" by (simp add: wf_field_descs_def)
    then interpret wf_d: wf_field_desc d .
    from TypDesc TypScalar wf_d.double_update show ?thesis
      by simp
  next
    case (TypAggregate fs)
    from wf have wf: "wf_field_descs (set (field_descs_list fs))" by (simp add: TypDesc TypAggregate)
    from ind have ind: "field_descs_independent (toplevel_field_descs_list fs)" by (simp add: TypDesc TypAggregate)
    from wf ind
    have "fst (apply_field_updates (map dt_trd fs) bs
            (fst (apply_field_updates (map dt_trd fs) bs' s))) =
          fst (apply_field_updates (map dt_trd fs) bs s)"
    proof (induct fs arbitrary: s bs bs')
      case Nil
      then show ?case by simp
    next
      case (Cons f fs')
      obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

      from Cons.prems f obtain
        wf_d: "wf_field_desc d" and
        wf_ft: "wf_field_descs (set (field_descs ft))" and
        wf_fs': "wf_field_descs (set (field_descs_list fs'))" and
        ind_d: "field_desc_independent (field_access d) (field_update d)
          (set (toplevel_field_descs_list fs'))" and
        ind_fs': "field_descs_independent (toplevel_field_descs_list fs')"
        by auto


      from wf_d interpret wf_d: wf_field_desc d .
      from field_update_apply_field_updates_commute [OF ind_d ind_fs']
      have d_ds'_commute: "field_update d bs
             (fst (apply_field_updates (map dt_trd fs') (drop (field_sz d) bs')
                     (field_update d bs' s))) =
            fst (apply_field_updates (map dt_trd fs') (drop (field_sz d) bs') (field_update d bs s))"
        by (simp add: toplevel_field_descs_list_map wf_d.double_update)


      note hyp = Cons.hyps [OF wf_fs' ind_fs', where bs="(drop (field_sz d) bs)" and s="(field_update d bs s)"]
      show ?case
        by (simp add: Cons f wf_d.access_result_size d_ds'_commute hyp)
    qed
    then show ?thesis by (simp add: TypDesc TypAggregate)
  qed
qed


lemma component_access_update:
  assumes wf:"wf_field_descs (set (field_descs t))"
  assumes ind: "field_descs_independent (toplevel_field_descs t)"
  shows "field_access (component_desc t) (field_update (component_desc t) bs s) bs' =
        field_access (component_desc t) (field_update (component_desc t) bs s') bs'"
proof (cases t)
  case (TypDesc algn st n)
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from TypDesc TypScalar have "d  set (field_descs t)" by simp
    with wf have "wf_field_desc d" by (simp add: wf_field_descs_def)
    then interpret wf_d: wf_field_desc d .
    from TypDesc TypScalar wf_d.access_update show ?thesis
      by simp
  next
    case (TypAggregate fs)
    from wf have wf: "wf_field_descs (set (field_descs_list fs))" by (simp add: TypDesc TypAggregate)
    from ind have ind: "field_descs_independent (toplevel_field_descs_list fs)" by (simp add: TypDesc TypAggregate)
    from wf ind
    have "concat (split_map
           (component_access_tuple (fst (apply_field_updates (map dt_trd fs) bs s))) fs bs') =
          concat (split_map
           (component_access_tuple (fst (apply_field_updates (map dt_trd fs) bs s'))) fs bs')"
    proof (induct fs arbitrary: bs s bs' s')
      case Nil
      then show ?case by simp
    next
      case (Cons f fs')
      obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

      from Cons.prems f obtain
        wf_d: "wf_field_desc d" and
        wf_ft: "wf_field_descs (set (field_descs ft))" and
        wf_fs': "wf_field_descs (set (field_descs_list fs'))" and
        ind_d: "field_desc_independent (field_access d) (field_update d)
          (set (toplevel_field_descs_list fs'))" and
        ind_fs': "field_descs_independent (toplevel_field_descs_list fs')"
        by auto

      from wf_d interpret wf_d: wf_field_desc d .

      note hyp = Cons.hyps [OF wf_fs' ind_fs']
      from field_update_apply_field_updates_commute [OF ind_d ind_fs']
      have eq1: "fst ((apply_field_updates (map dt_trd fs') (drop (field_sz d) bs))
                 (field_update d bs s)) =
               field_update d bs
                 (fst (apply_field_updates (map dt_trd fs') (drop (field_sz d) bs) s))"
           (is "_ = ?rhs")
        by (simp add: toplevel_field_descs_list_map)
      have eq2: "field_access d ?rhs bs' = field_access d (field_update d bs s) bs'"
        by (simp add: wf_d.access_update)
      from field_update_apply_field_updates_commute [OF ind_d ind_fs']
      have eq3: "fst (apply_field_updates (map dt_trd fs') (drop (field_sz d) bs)
                   (field_update d bs s')) =
                 field_update d bs
                  (fst (apply_field_updates (map dt_trd fs') (drop (field_sz d) bs) s'))"
           (is "_ = ?rhs")
        by (simp add: toplevel_field_descs_list_map)
      have eq4: "field_access d ?rhs bs' = field_access d (field_update d bs s) bs'"
        by (simp add: wf_d.access_update)
      show ?case
        apply (simp add: f eq1 eq2 eq3 eq4 wf_d.access_result_size)
        apply (simp only: eq1 [symmetric] )
        apply (simp only: eq3 [symmetric] )
        apply (simp add: hyp)
        done
    qed

    then show ?thesis
      by (simp add: TypDesc TypAggregate)
  qed
qed

lemma sum_nat_foldl: "(n::nat) + foldl (+) m xs = foldl (+) (n + m) xs"
  by (induct xs arbitrary: n m) (auto simp add: semiring_normalization_rules(25))

lemma sum_nat_foldl_le: "(n::nat)  foldl (+) n xs"
  by (induct xs arbitrary: n) (auto elim: add_leE)

lemma sum_add_sub_foldl: "foldl (+) (m + n) ns - n = foldl (+) (m::nat) ns"
  apply (induct ns arbitrary: m n)
   apply simp
  apply (metis diff_add_inverse2 semiring_normalization_rules(24) sum_nat_foldl)
  done

lemma sum_sub_zero_foldl: "foldl (+) n ns - (n::nat) = foldl (+) 0 ns"
  using sum_add_sub_foldl [where m=0, simplified]
  by simp

lemma drop_take_sub: "drop n (take (foldl (+) n ns) bs) = take (foldl (+) 0 ns) (drop n bs)"
  by (simp add: drop_take sum_sub_zero_foldl)


lemma component_access_size:
  assumes wf: "wf_field_descs (set (field_descs t))"
  shows "field_access (component_desc t) s (take (field_sz (component_desc t)) bs) =
         field_access (component_desc t) s bs"
proof (cases t)
  case (TypDesc algn st n)
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from TypDesc TypScalar have "d  set (field_descs t)" by simp
    with wf have "wf_field_desc d" by (simp add: wf_field_descs_def)
    then interpret wf_d: wf_field_desc d .
    from TypDesc TypScalar wf_d.access_size show ?thesis
      by simp
  next
    case (TypAggregate fs)
    from wf have wf: "wf_field_descs (set (field_descs_list fs))" by (simp add: TypDesc TypAggregate)
    from wf
    have "concat (split_map (component_access_tuple s) fs
            (take (foldl (+) 0 (map (field_sz  dt_trd) fs)) bs)) =
          concat (split_map (component_access_tuple s) fs bs)"
    proof (induct fs arbitrary: s bs)
      case Nil
      then show ?case by simp
    next
      case (Cons f fs')
      obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

      from Cons.prems f obtain
        wf_d: "wf_field_desc d" and
        wf_ft: "wf_field_descs (set (field_descs ft))" and
        wf_fs': "wf_field_descs (set (field_descs_list fs'))"
        by auto

      from wf_d interpret wf_d: wf_field_desc d .

      have "field_sz d  foldl (+) (field_sz d) (map (λf'. field_sz (dt_trd f')) fs')" (is "?n  ?m")
        by (rule sum_nat_foldl_le)
      then
      have eq1: "take ?n (take ?m bs) = take ?n bs"
        by (simp add: min_def)

      from wf_d.access_size [where bs="take ?m bs"]
      have "field_access d s (take ?m bs) = field_access d s (take ?n (take ?m bs))"
        by (simp)
      also have " = field_access d s (take ?n bs)" by (simp only: eq1)
      also have " = field_access d s bs" by (simp add: wf_d.access_size)
      finally
      have eq_head: "field_access d s (take (foldl (+) (field_sz d) (map (λf'. field_sz (dt_trd f')) fs')) bs) =
                     field_access d s bs" .

      from Cons.hyps [OF wf_fs']
      show ?case
        by (simp add: f eq_head wf_d.access_result_size drop_take_sub)
    qed

    then show ?thesis
      by (simp add: TypDesc TypAggregate)
  qed
qed

lemma component_access_result_size:
  assumes wf: "wf_field_descs (set (field_descs t))"
  shows "length (field_access (component_desc t) s bs) = field_sz (component_desc t)"
proof (cases t)
  case (TypDesc algn st n)
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from TypDesc TypScalar have "d  set (field_descs t)" by simp
    with wf have "wf_field_desc d" by (simp add: wf_field_descs_def)
    then interpret wf_d: wf_field_desc d .
    from TypDesc TypScalar wf_d.access_result_size show ?thesis
      by simp
  next
    case (TypAggregate fs)
    from wf have wf: "wf_field_descs (set (field_descs_list fs))" by (simp add: TypDesc TypAggregate)
    from wf
    have "length (concat (split_map (component_access_tuple s) fs bs)) =
            foldl (+) 0 (map (field_sz  dt_trd) fs)"
    proof (induct fs arbitrary: s bs)
      case Nil
      then show ?case by simp
    next
      case (Cons f fs')
      obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

      from Cons.prems f obtain
        wf_d: "wf_field_desc d" and
        wf_ft: "wf_field_descs (set (field_descs ft))" and
        wf_fs': "wf_field_descs (set (field_descs_list fs'))"
        by auto

      from wf_d interpret wf_d: wf_field_desc d .

      note hyp = Cons.hyps [OF wf_fs']
      show ?case
        by (simp add: hyp wf_d.access_result_size f sum_nat_foldl)
    qed
    then show ?thesis by (simp add: TypDesc TypAggregate)
  qed
qed

lemma component_update_size:
  assumes wf: "wf_field_descs (set (field_descs t))"
  shows "field_update (component_desc t) (take (field_sz (component_desc t)) bs) s =
         field_update (component_desc t) bs s"
proof (cases t)
  case (TypDesc algn st n)
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from TypDesc TypScalar have "d  set (field_descs t)" by simp
    with wf have "wf_field_desc d" by (simp add: wf_field_descs_def)
    then interpret wf_d: wf_field_desc d .
    from TypDesc TypScalar wf_d.update_size show ?thesis
      by simp
  next
    case (TypAggregate fs)
    from wf have wf: "wf_field_descs (set (field_descs_list fs))" by (simp add: TypDesc TypAggregate)
    then have "fst (apply_field_updates (map dt_trd fs)
                 (take (foldl (+) 0 (map (field_sz  dt_trd) fs)) bs) s) =
               fst (apply_field_updates (map dt_trd fs) bs s)"
    proof (induct fs arbitrary: s bs)
      case Nil
      then show ?case by simp
    next
      case (Cons f fs')
      obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

      from Cons.prems f obtain
        wf_d: "wf_field_desc d" and
        wf_ft: "wf_field_descs (set (field_descs ft))" and
        wf_fs': "wf_field_descs (set (field_descs_list fs'))"
        by auto

      from wf_d interpret wf_d: wf_field_desc d .

      have "field_sz d  foldl (+) (field_sz d) (map (λa. field_sz (dt_trd a)) fs')" (is "?n  ?m")
        by (rule sum_nat_foldl_le)
      then
      have eq1: "take ?n (take ?m bs) = take ?n bs"
        by (simp add: min_def)

      from wf_d.update_size [where bs="take ?m bs"]
      have "field_update d ((take ?m) bs) s = field_update d (take ?n (take ?m bs)) s" by simp
      also have " = field_update d (take ?n bs) s" by (simp only: eq1)
      also from wf_d.update_size [where bs=bs]
      have " = field_update d bs s" by simp
      finally have eq: "field_update d ((take ?m) bs) s = field_update d bs s" .


      note hyp = Cons.hyps [OF wf_fs', simplified comp_def]

      show ?case
        apply (simp add: f )
        apply (simp only: eq)
        apply (simp only: drop_take_sub)
        apply (simp only: hyp)
        done
    qed
    then show ?thesis by (simp add: TypDesc TypAggregate)
  qed
qed


lemma apply_field_updates_access_cancel:
  assumes wf: "wf_field_descs (set (field_descs_list fs))"
  assumes ind: "field_descs_independent (toplevel_field_descs_list fs)"
  shows "fst (apply_field_updates (map dt_trd fs) (concat (split_map (component_access_tuple v) fs bs)) v) = v"
  using wf ind
proof (induct fs arbitrary: v bs)
  case Nil
  then show ?case by simp
next
  case (Cons f fs')
  obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp
  from Cons.prems f obtain
    wf_d: "wf_field_desc d" and
    wf_ft: "wf_field_descs (set (field_descs ft))" and
    wf_fs': "wf_field_descs (set (field_descs_list fs'))" and
    ind_d: "field_desc_independent (field_access d) (field_update d)
            (set (toplevel_field_descs_list fs'))" and
    ind_fs': "field_descs_independent (toplevel_field_descs_list fs')"
    by auto

  from wf_d interpret wf_d: wf_field_desc d .

  from wf_d.update_size [of "(field_access d v bs @
     concat (split_map (component_access_tuple v) fs' (drop (length (field_access d v bs)) bs)))"]
  have eq1: "field_update d
            (field_access d v bs @
               concat
                 (split_map (component_access_tuple v) fs'
                  (drop (length (field_access d v bs)) bs)))
         v = field_update d (field_access d v bs) v"

    by  (simp add: wf_d.access_result_size)

  note hyp = Cons.hyps [OF wf_fs' ind_fs']
  show ?case apply (simp add: Cons.prems f)
    apply (simp add: eq1)
    apply (simp add: wf_d.access_result_size wf_d.update_access hyp)
    done
qed

lemma apply_field_updates_double:
  assumes wf: "wf_field_descs (set (field_descs_list fs))"
  assumes ind: "field_descs_independent (toplevel_field_descs_list fs)"
  shows "fst (apply_field_updates (map dt_trd fs) bs
           (fst (apply_field_updates (map dt_trd fs) bs' v))) =
         fst (apply_field_updates (map dt_trd fs) bs v)"
  using wf ind
proof (induct fs arbitrary: v bs bs')
  case Nil
  then show ?case by simp
next
  case (Cons f fs')
  obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp
  from Cons.prems f obtain
    wf_d: "wf_field_desc d" and
    wf_ft: "wf_field_descs (set (field_descs ft))" and
    wf_fs': "wf_field_descs (set (field_descs_list fs'))" and
    ind_d: "field_desc_independent (field_access d) (field_update d)
            (set (toplevel_field_descs_list fs'))" and
    ind_fs': "field_descs_independent (toplevel_field_descs_list fs')"
    by auto

  note commute = field_update_apply_field_updates_commute [OF ind_d ind_fs', simplified toplevel_field_descs_list_map]
  note hyp = Cons.hyps [OF wf_fs' ind_fs']
  from wf_d interpret wf_d: wf_field_desc d .
  show ?case apply (simp add: Cons.prems f)
    by (simp add: commute hyp wf_d.double_update)
qed

lemma list_append_eq_split_conv: "length xs1 = length xs2  xs1 @ ys1 = xs2 @ ys2  xs1 = xs2  ys1 = ys2"
  by auto

lemma component_complement_padding:
  assumes wf: "wf_field_descs (set (field_descs t))"
  assumes ind: "field_descs_independent (toplevel_field_descs t)"
  assumes i_bound: "i < field_sz (component_desc t)"
  shows "padding_base.is_padding_byte (field_access (component_desc t))
          (field_update (component_desc t)) (field_sz (component_desc t)) i 
         padding_base.is_value_byte (field_access (component_desc t))
          (field_update (component_desc t)) (field_sz (component_desc t)) i"
proof (cases t)
  case (TypDesc algn st n)
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from TypDesc TypScalar have "d  set (field_descs t)" by simp
    with wf have "wf_field_desc d" by (simp add: wf_field_descs_def)
    then interpret wf_d: wf_field_desc d .
    from TypDesc TypScalar wf_d.complement show ?thesis
      using i_bound
      by auto
  next
    case (TypAggregate fs)
    from wf have wf: "wf_field_descs (set (field_descs_list fs))" by (simp add: TypDesc TypAggregate)
    from ind have ind: "field_descs_independent (toplevel_field_descs_list fs)" by (simp add: TypDesc TypAggregate)
    from i_bound have i_bound': "i < foldl (+) 0 (map (field_sz  dt_trd) fs)" by (simp add: TypDesc TypAggregate)
    from wf ind i_bound'
    have "padding_base.is_padding_byte (component_access_struct (TypAggregate fs))
            (component_update_struct (TypAggregate fs))
            (foldl (+) 0 (map (field_sz  dt_trd) fs)) i =
          (¬ padding_base.is_value_byte (component_access_struct (TypAggregate fs))
            (component_update_struct (TypAggregate fs))
            (foldl (+) 0 (map (field_sz  dt_trd) fs)) i)"
    proof (induct fs arbitrary: i)
      case Nil
      then show ?case by (simp add: padding_base.is_padding_byte_def padding_base.is_value_byte_def)
    next
      case (Cons f fs')
      obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp
      from Cons.prems f obtain
        wf_d: "wf_field_desc d" and
        wf_ft: "wf_field_descs (set (field_descs ft))" and
        wf_fs': "wf_field_descs (set (field_descs_list fs'))" and
        ind_d: "field_desc_independent (field_access d) (field_update d)
          (set (toplevel_field_descs_list fs'))" and
        ind_fs': "field_descs_independent (toplevel_field_descs_list fs')" and
        i_bound: "i < foldl (+) (field_sz d) (map (λa. field_sz (dt_trd a)) fs')"
        by (auto)

      have split_foldl:
        "(foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) =
           field_sz d + (foldl (+) 0 (map (field_sz  dt_trd) fs'))"
        by (auto simp add: f sum_nat_foldl)

      from wf_d interpret wf_d: wf_field_desc d .

      note commute = field_update_apply_field_updates_commute [OF ind_d ind_fs', symmetric, simplified toplevel_field_descs_list_map]
      note hyp = Cons.hyps [OF wf_fs' ind_fs']
      show ?case
      proof (cases "i < field_sz d")
        case True
        note i_in_d = this
        show ?thesis
        proof (cases "wf_d.is_padding_byte i")
          case True
          note is_padding_d = this
          with True wf_d.complement i_in_d have not_value_d: "¬ wf_d.is_value_byte i" by simp
          have "padding_base.is_padding_byte
                 (component_access_struct (TypAggregate (f # fs')))
                 (component_update_struct (TypAggregate (f # fs')))
                (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
          proof (rule padding_base.is_padding_byteI)
            show "i < foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
              using i_bound
              by (simp add: f comp_def)
          next
            fix v::'a and bs::"byte list"
            assume "i < foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            assume "length bs = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            hence lbs: "length bs = foldl (+) (field_sz d) (map (λx. field_sz (dt_trd x)) fs')"
              by (simp add: f comp_def)
            hence lbs': "field_sz d  length bs"
              using sum_nat_foldl_le by auto
            hence ltake: "length (take (field_sz d) bs) = field_sz d" by simp
            from  wf_d.access_size
            have acc_d_take: "field_access d v bs = field_access d v (take (field_sz d) bs)" by simp
            from wf_d.access_result_size have acc_d_sz: "length (field_access d v bs) = field_sz d" .
            have "field_access d v bs ! i = bs ! i"
              using i_in_d
              by (simp add:  acc_d_take wf_d.access_result_size wf_d.is_padding_byte_acc_id [OF is_padding_d ltake])
            then
            show "component_access_struct (TypAggregate (f # fs')) v bs ! i = bs ! i"
              using i_bound lbs i_in_d
              by (simp add: Cons f nth_append acc_d_sz)
          next
            fix v::'a and bs::"byte list" and b::byte
            assume "i < foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            assume "length bs = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            hence lbs: "length bs = foldl (+) (field_sz d) (map (λx. field_sz (dt_trd x)) fs')"
              by (simp add: f comp_def)
            hence lbs': "field_sz d  length bs"
              using sum_nat_foldl_le by auto
            with i_in_d have drop_eq: "(drop (field_sz d) (bs[i := b])) = drop (field_sz d) bs"
              by (meson drop_update_cancel)
            from lbs' have ltake: "length (take (field_sz d) bs) = field_sz d" by simp
            have "(field_update d (bs[i := b]) v) = field_update d bs v"
              apply (subst (1 2) wf_d.update_size [symmetric])
              using wf_d.is_padding_byte_upd_eq [OF is_padding_d ltake] ltake
              by (metis take_update_swap)
            then
            show "component_update_struct (TypAggregate (f # fs')) bs v =
               component_update_struct (TypAggregate (f # fs')) (bs[i := b]) v"
              by (simp add: Cons f drop_eq)
          qed
          moreover
          {
            assume is_value: "padding_base.is_value_byte
                 (component_access_struct (TypAggregate (f # fs')))
                 (component_update_struct (TypAggregate (f # fs')))
                (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
            have "wf_d.is_value_byte i"
            proof (rule wf_d.is_value_byteI)
              show "i < field_sz d" by (rule i_in_d)
            next
              fix v::'a and bs::"byte list" and bs'::"byte list"
              assume lbs: "length bs = field_sz d"
              assume lbs': "length bs' = field_sz d"
              obtain xbs where
                lxbs:"length xbs = (foldl (+) 0 (map (field_sz  dt_trd) (f # fs')))" and
                bs: "bs = take (field_sz d) xbs" and
                split_xbs: "xbs = take (field_sz d) xbs @ drop (field_sz d) xbs"
                using lbs append_eq_conv_conj
                unfolding split_foldl
                by (metis (no_types, opaque_lifting) Ex_list_of_length length_append)
              obtain xbs' where
                lxbs':"length xbs' = (foldl (+) 0 (map (field_sz  dt_trd) (f # fs')))" and
                bs': "bs' = take (field_sz d) xbs'" and
                split_xbs': "xbs' = take (field_sz d) xbs' @ drop (field_sz d) xbs'"
                using lbs' append_eq_conv_conj
                unfolding split_foldl
                by (metis (no_types, opaque_lifting) Ex_list_of_length length_append)
              have xbs_i: "xbs ! i = bs ! i"
                using bs split_xbs'
                by (simp add: bs i_in_d)

              have upd_xbs: "field_update d xbs v = field_update d bs v"
                apply (subst split_xbs)
                apply (subst wf_d.update_size [symmetric])
                apply simp
                apply (simp add: bs [symmetric])
                done

              from commute [where bs'="(drop (field_sz d) xbs)" and bs = bs and s=v]
              have acc_upd: "field_access d
                     (fst (apply_field_updates (map dt_trd fs') (drop (field_sz d) xbs)
                     (field_update d bs v)))
                     bs' = field_access d (field_update d bs v) bs'"
                using wf_d.access_update by auto


              from padding_base.is_value_byte_acc_upd_cancel [OF is_value lxbs lxbs']
              have "component_access_struct (TypAggregate (f # fs'))
                     (component_update_struct (TypAggregate (f # fs')) xbs v) xbs' !
                     i = xbs ! i" .
              then
              show "field_access d (field_update d bs v) bs' ! i = bs ! i"
                using lbs'  lbs' i_in_d
                apply (simp add: f xbs_i)
                apply (subst (asm) wf_d.access_size [symmetric])
                apply (simp add: bs' [symmetric])
                apply (simp add: wf_d.access_result_size nth_append upd_xbs acc_upd)
                done

            next
              fix v::'a and bs::"byte list" and b::byte
              assume lbs: "length bs = field_sz d"
              obtain xbs where
                lxbs:"length xbs = (foldl (+) 0 (map (field_sz  dt_trd) (f # fs')))" and
                bs: "bs = take (field_sz d) xbs" and
                split_xbs: "xbs = take (field_sz d) xbs @ drop (field_sz d) xbs"
                using lbs append_eq_conv_conj
                unfolding split_foldl
                by (metis (no_types, opaque_lifting) Ex_list_of_length length_append)
              have eq1: "field_access d v xbs = field_access d v bs"
                using bs wf_d.access_size by simp
              have eq2: "field_access d v (xbs[i := b]) = field_access d v (bs[i := b])"
                using i_in_d bs
                by (metis take_update_swap wf_d.access_size)

              from padding_base.is_value_byte_acc_eq [OF is_value lxbs]
              have "component_access_struct (TypAggregate (f # fs')) v xbs =
                component_access_struct (TypAggregate (f # fs')) v (xbs[i := b])" .
              then
              show "field_access d v bs = field_access d v (bs[i := b])"
                apply (simp add: f)
                apply (subst (asm) list_append_eq_split_conv)
                 apply (simp add: wf_d.access_result_size)
                apply (clarsimp simp add: eq1 eq2)
                done
            qed
          }
          then
          have "¬ padding_base.is_value_byte
                 (component_access_struct (TypAggregate (f # fs')))
                 (component_update_struct (TypAggregate (f # fs')))
                (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
            using not_value_d
             by blast
          ultimately show ?thesis by blast
        next
          case False
          note not_padding = this
          with wf_d.complement i_in_d have is_value: "wf_d.is_value_byte i" by simp
          have "padding_base.is_value_byte
            (component_access_struct (TypAggregate (f # fs')))
            (component_update_struct (TypAggregate (f # fs')))
            (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
          proof (rule padding_base.is_value_byteI)
            show "i < foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
              using i_bound by (simp add: f comp_def)
          next
            fix v::'a and bs::"byte list" and bs'::"byte list"
            assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            assume lbs': "length bs' = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            from lbs have lbs_take: "length (take (field_sz d) bs) = field_sz d"
              using lbs split_foldl by (simp add: f comp_def)
            from lbs' have lbs'_take: "length (take (field_sz d) bs') = field_sz d"
              using lbs split_foldl by (simp add: f comp_def)

            show "component_access_struct (TypAggregate (f # fs'))
                   (component_update_struct (TypAggregate (f # fs')) bs v) bs' !
                   i = bs ! i"
              apply (simp add: f)
              apply (subst wf_d.access_size [symmetric])
              using i_in_d
              apply (simp add: wf_d.access_result_size nth_append)
              apply (subst commute)
              apply (subst wf_d.access_update [where s'=v])
              using wf_d.is_value_byte_acc_upd_cancel [OF is_value lbs_take lbs'_take, of v]
              apply (simp add: wf_d.update_size)
              done
          next
            fix v::'a and bs::"byte list" and b::byte
            assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            from lbs have lbs_take: "length (take (field_sz d) bs) = field_sz d"
              using lbs split_foldl by (simp add: f comp_def)
            have acc_eq: "field_access d v bs = field_access d v (bs[i:=b])"
              apply (subst (1 2) wf_d.access_size [symmetric])
              using wf_d.is_value_byte_acc_eq [OF is_value lbs_take] i_in_d
              by (metis take_update_swap)

            show "component_access_struct (TypAggregate (f # fs')) v bs =
              component_access_struct (TypAggregate (f # fs')) v (bs[i := b])"
              apply (simp add: f acc_eq)
              using lbs_take i_in_d
              by (simp add: wf_d.access_result_size)
          qed
          moreover
          {
            assume is_padding: "padding_base.is_padding_byte
              (component_access_struct (TypAggregate (f # fs')))
              (component_update_struct (TypAggregate (f # fs')))
              (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
            have "wf_d.is_padding_byte i"
            proof (rule wf_d.is_padding_byteI)
              from i_in_d show "i < field_sz d" .
            next
              fix v::'a and bs::"byte list"
              assume lbs: "length bs = field_sz d"
              obtain xbs where
                lxbs:"length xbs = (foldl (+) 0 (map (field_sz  dt_trd) (f # fs')))" and
                bs: "bs = take (field_sz d) xbs" and
                split_xbs: "xbs = take (field_sz d) xbs @ drop (field_sz d) xbs"
                using lbs append_eq_conv_conj
                unfolding split_foldl
                by (metis (no_types, opaque_lifting) Ex_list_of_length length_append)
              from padding_base.is_padding_byte_acc_eq [OF is_padding lxbs, where v=v]

              show "field_access d v bs ! i = bs ! i"
                apply (simp add: f)
                by (simp add: bs i_in_d nth_append wf_d.access_result_size wf_d.access_size)
            next
              fix v::'a and bs::"byte list" and b::byte
              assume lbs: "length bs = field_sz d"
              obtain xbs where
                lxbs:"length xbs = (foldl (+) 0 (map (field_sz  dt_trd) (f # fs')))" and
                bs: "bs = take (field_sz d) xbs" and
                split_xbs: "xbs = take (field_sz d) xbs @ drop (field_sz d) xbs"
                using lbs append_eq_conv_conj
                unfolding split_foldl
                by (metis (no_types, opaque_lifting) Ex_list_of_length length_append)
              from padding_base.is_padding_byte_upd_eq [OF is_padding lxbs, where v=v]
              show "field_update d bs v = field_update d (bs[i := b]) v"
                apply (simp add: f)
                by (metis bs commute take_update_swap wf_d.access_update wf_d.double_update
                    wf_d.update_access wf_d.update_size_ext)
            qed
          }
          with not_padding
          have "¬ padding_base.is_padding_byte
            (component_access_struct (TypAggregate (f # fs')))
            (component_update_struct (TypAggregate (f # fs')))
            (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i" by blast
          ultimately show ?thesis by blast
        qed
      next
        case False
        note i_notin_d = this
        with i_bound obtain n j where
          j_bound: "j < foldl (+) 0 (map (field_sz  dt_trd) fs')" and
          j: "j = i - field_sz d" and
          i: "i = j + field_sz d"
          apply (subst (asm) (2) sum_nat_foldl [where m = 0, simplified, symmetric])
          by (fastforce simp add: comp_def)
        note complement_fs'_j = hyp [OF j_bound]
        show ?thesis
        proof (cases "padding_base.is_padding_byte (component_access_struct (TypAggregate fs'))
                        (component_update_struct (TypAggregate fs'))
                        (foldl (+) 0 (map (field_sz  dt_trd) fs')) j ")
          case True
          note is_padding_j = this
          with complement_fs'_j have not_is_value_j:
            "¬ padding_base.is_value_byte (component_access_struct (TypAggregate fs'))
                 (component_update_struct (TypAggregate fs'))
                 (foldl (+) 0 (map (field_sz  dt_trd) fs')) j" by blast
          have "padding_base.is_padding_byte
            (component_access_struct (TypAggregate (f # fs')))
            (component_update_struct (TypAggregate (f # fs')))
            (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
          proof (rule padding_base.is_padding_byteI)
            from i_bound show "i < foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))" by (simp add: f comp_def)
          next
            fix v::'a and bs::"byte list"
            assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            from lbs have lbs_drop: "length (drop (field_sz d) bs) = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              apply (subst (asm) split_foldl)
              apply (simp add: f)
              done
            show "component_access_struct (TypAggregate (f # fs')) v bs ! i = bs ! i"
              apply (simp add: f)
              using i_notin_d i
              apply (simp add: nth_append wf_d.access_result_size)
              using padding_base.is_padding_byte_acc_eq [OF is_padding_j lbs_drop, of v]
              apply simp
              by (metis add.commute lbs le_add_same_cancel1 nth_drop split_foldl sum_nat_foldl_le)
          next
            fix v::'a and bs::"byte list" and b::byte
            assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            from lbs have lbs_drop: "length (drop (field_sz d) bs) = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              apply (subst (asm) split_foldl)
              apply (simp add: f)
              done
            from i_notin_d
            have tk_eq: "take (field_sz d) (bs[i := b]) = take (field_sz d) bs"
              by (meson not_less take_update_cancel)
            have upd_eq: "field_update d bs v = field_update d (bs[i := b]) v"
              apply (subst (1 2) wf_d.update_size [symmetric])
              apply (simp add: tk_eq)
              done
            show "component_update_struct (TypAggregate (f # fs')) bs v =
              component_update_struct (TypAggregate (f # fs')) (bs[i := b]) v"
              apply (simp add: f)
              apply (simp add: upd_eq [symmetric])
              using padding_base.is_padding_byte_upd_eq [OF is_padding_j lbs_drop, where v= "(field_update d bs v)" and b=b]
              apply (simp)
              by (metis drop_update_swap i j le_add2)
          qed
          moreover
          {
            assume is_value: "padding_base.is_value_byte
              (component_access_struct (TypAggregate (f # fs')))
              (component_update_struct (TypAggregate (f # fs')))
              (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
            have "padding_base.is_value_byte (component_access_struct (TypAggregate fs'))
                 (component_update_struct (TypAggregate fs'))
                 (foldl (+) 0 (map (field_sz  dt_trd) fs')) j"
            proof (rule padding_base.is_value_byteI)
              from j_bound show "j < foldl (+) 0 (map (field_sz  dt_trd) fs')" .
            next
              fix v::'a and bs::"byte list" and bs'::"byte list"
              assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              assume lbs': "length bs' = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              obtain d_bs v_bs where v_bs: "v_bs = field_access d v d_bs" and
                l_v_bs: "length v_bs = field_sz d"
                using wf_d.access_result_size by auto
              obtain xbs where
                xbs_def: "xbs = v_bs @ bs" and
                xbs: "xbs = take (field_sz d) xbs @ bs" and
                lxbs: "length xbs = field_sz d + length bs"
                by (simp add: l_v_bs)
              obtain xbs' where
                xbs': "xbs' = take (field_sz d) xbs' @ bs'" and
                lxbs': "length xbs' = field_sz d + length bs'"
                by (metis Ex_list_of_length append_eq_conv_conj length_append)
              have xbs_i: "xbs ! i = bs ! j"
                by (metis add.commute append_take_drop_id i le_add2 lxbs nth_drop same_append_eq xbs)
              have drop_xbs': "drop (field_sz d) xbs' = bs'"
                by (metis append_take_drop_id same_append_eq xbs')
              have drop_xbs: "drop (field_sz d) xbs = bs"
                by (metis append_take_drop_id same_append_eq xbs)
              have upd_xbs: "field_update d xbs v = v"
                by (simp add: v_bs wf_d.update_access_append xbs_def)
              show "component_access_struct (TypAggregate fs')
                     (component_update_struct (TypAggregate fs') bs v) bs' !
                     j = bs ! j"
                apply (simp )
                using padding_base.is_value_byte_acc_upd_cancel
                  [OF is_value, where bs=xbs and bs'=xbs', simplified split_foldl,
                    OF lxbs [simplified lbs] lxbs' [simplified lbs'], where v = v]
                apply (simp add: xbs_i f nth_append wf_d.access_result_size i_notin_d drop_xbs' drop_xbs
                    j [symmetric] upd_xbs)
                done
            next
              fix v::'a and bs::"byte list" and b::"byte"
              assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              obtain d_bs v_bs where v_bs: "v_bs = field_access d v d_bs" and
                l_v_bs: "length v_bs = field_sz d"
                using wf_d.access_result_size by auto
              obtain xbs where
                xbs_def: "xbs = v_bs @ bs" and
                xbs: "xbs = take (field_sz d) xbs @ bs" and
                lxbs: "length xbs = field_sz d + length bs"
                by (simp add: l_v_bs)
              have xbs_i: "xbs[i := b] = bs [j := b]"

                by (metis calculation component_sz_struct_aggregate is_value l_v_bs lbs len_gt_0
                    length_append less_irrefl padding_base.is_padding_byte_def padding_base.is_value_byte_upd_neq
                    split_foldl word_power_less_1 xbs_def)
              have drop_xbs: "drop (length (field_access d v xbs)) xbs = bs"
                by (simp add: l_v_bs wf_d.access_result_size xbs_def)

              show "component_access_struct (TypAggregate fs') v bs =
                component_access_struct (TypAggregate fs') v (bs[j := b])"
                apply (simp )
                using padding_base.is_value_byte_acc_eq [OF is_value, where bs=xbs, simplified split_foldl,
                    OF lxbs [simplified lbs], where v=v and b=b]
                apply (simp add: f)
                apply (subst (asm) list_append_eq_split_conv)
                 apply (simp add: wf_d.access_result_size)
                apply (clarsimp simp add: drop_xbs)
                apply (simp add: xbs_i)
                by (metis (no_types, opaque_lifting) append_Nil append_eq_append_conv append_eq_conv_conj
                    l_v_bs length_list_update wf_d.access_result_size xbs_def xbs_i)
            qed
          }
          with not_is_value_j
          have "¬ padding_base.is_value_byte
            (component_access_struct (TypAggregate (f # fs')))
            (component_update_struct (TypAggregate (f # fs')))
            (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i" by blast

          ultimately show ?thesis by blast
        next
          case False
          note not_is_padding_j = this
          with complement_fs'_j have is_value_j:
            "padding_base.is_value_byte (component_access_struct (TypAggregate fs'))
                 (component_update_struct (TypAggregate fs'))
                 (foldl (+) 0 (map (field_sz  dt_trd) fs')) j" by blast
          have "padding_base.is_value_byte
                  (component_access_struct (TypAggregate (f # fs')))
                  (component_update_struct (TypAggregate (f # fs')))
                  (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
          proof (rule padding_base.is_value_byteI)
            from i_bound show "i < foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))" by (simp add: f comp_def)
          next
            fix v::'a and bs::"byte list" and bs'::"byte list"
            assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            assume lbs': "length bs' = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            from lbs have lbs_drop: "length (drop (field_sz d) bs) = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              apply (subst (asm) split_foldl)
              apply (simp add: f)
              done
            from lbs' have lbs'_drop: "length (drop (field_sz d) bs') = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              apply (subst (asm) split_foldl)
              apply (simp add: f)
              done
            have drop_j: "drop (field_sz d) bs ! j = bs ! i"
              by (metis add.commute i lbs le_add_same_cancel1 nth_drop split_foldl zero_le)
            show "component_access_struct (TypAggregate (f # fs'))
                    (component_update_struct (TypAggregate (f # fs')) bs v) bs' !
                    i = bs ! i"
              apply (simp add: f nth_append i_notin_d wf_d.access_result_size j[symmetric])
              using padding_base.is_value_byte_acc_upd_cancel [OF is_value_j lbs_drop lbs'_drop, where v = "field_update d bs v"]
              apply (simp add: drop_j)
              done
          next
            fix v::'a and bs::"byte list" and b::"byte"
            assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))"
            from lbs have lbs_drop: "length (drop (field_sz d) bs) = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              apply (subst (asm) split_foldl)
              apply (simp add: f)
              done
            have acc_eq: "field_access d v bs = field_access d v (bs[i := b])"
              by (metis i le_add2 take_update_cancel wf_d.access_size)
            show "component_access_struct (TypAggregate (f # fs')) v bs =
                   component_access_struct (TypAggregate (f # fs')) v (bs[i := b])"
              apply (simp add: f)
              apply (subst list_append_eq_split_conv)
               apply (simp add: wf_d.access_result_size)
              apply (simp add: acc_eq)
              using padding_base.is_value_byte_acc_eq [OF is_value_j lbs_drop, where v="v" and b=b]
              apply simp
              by (metis drop_update_swap i j le_add2 wf_d.access_result_size)
          qed
          moreover
          {
            assume is_padding: "padding_base.is_padding_byte
                      (component_access_struct (TypAggregate (f # fs')))
                      (component_update_struct (TypAggregate (f # fs')))
                      (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i"
            have "padding_base.is_padding_byte (component_access_struct (TypAggregate fs'))
                    (component_update_struct (TypAggregate fs'))
                    (foldl (+) 0 (map (field_sz  dt_trd) fs')) j"
            proof (rule padding_base.is_padding_byteI)
              from j_bound show "j < foldl (+) 0 (map (field_sz  dt_trd) fs')" .
            next
              fix v::'a and bs::"byte list"
              assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              obtain d_bs v_bs where v_bs: "v_bs = field_access d v d_bs" and
                l_v_bs: "length v_bs = field_sz d"
                using wf_d.access_result_size by auto
              obtain xbs where
                xbs_def: "xbs = v_bs @ bs" and
                xbs: "xbs = take (field_sz d) xbs @ bs" and
                lxbs: "length xbs = field_sz d + length bs"
                by (simp add: l_v_bs)
              have drop_eq: "(drop (field_sz d) xbs) = bs"
                by (simp add: l_v_bs xbs_def)
              have xbs_i: "xbs ! i = bs ! j"
                by (simp add: i_notin_d j l_v_bs nth_append xbs_def)
              show "component_access_struct (TypAggregate fs') v bs ! j = bs ! j"
                using padding_base.is_padding_byte_acc_eq [OF is_padding, where bs=xbs, simplified split_foldl,
                    OF lxbs [simplified lbs], where v = v]
                apply (simp add: f nth_append wf_d.access_result_size i_notin_d j [symmetric] drop_eq xbs_i)
                done
            next
              fix v::'a and bs::"byte list" and b::byte
              assume lbs: "length bs = foldl (+) 0 (map (field_sz  dt_trd) fs')"
              obtain d_bs v_bs where v_bs: "v_bs = field_access d v d_bs" and
                l_v_bs: "length v_bs = field_sz d"
                using wf_d.access_result_size by auto
              obtain xbs where
                xbs_def: "xbs = v_bs @ bs" and
                xbs: "xbs = take (field_sz d) xbs @ bs" and
                lxbs: "length xbs = field_sz d + length bs"
                by (simp add: l_v_bs)
              have drop_eq: "(drop (field_sz d) xbs) = bs"
                by (simp add: l_v_bs xbs_def)

              have xbs_i: "xbs [i := b] = bs [j := b]"
                by (metis calculation is_padding l_v_bs lbs len_gt_0 length_append less_irrefl
                    padding_base.is_padding_byte_acc_neq padding_base.is_value_byte_def split_foldl word_power_less_1 xbs_def)
              have upd_eq: "(field_update d xbs v) = v"
                by (simp add: v_bs wf_d.update_access_append xbs_def)
              have eq: "fst (apply_field_updates (map dt_trd fs') (bs[j := b]) v) = fst (apply_field_updates (map dt_trd fs') bs v)"
                by (metis calculation is_padding lbs list_update_id lxbs padding_base.is_padding_byte_acc_neq
                    padding_base.is_value_byte_acc_eq split_foldl)
              show "component_update_struct (TypAggregate fs') bs v =
                      component_update_struct (TypAggregate fs') (bs[j := b]) v"
                using padding_base.is_padding_byte_upd_eq [OF is_padding, where bs=xbs, simplified split_foldl,
                    OF lxbs [simplified lbs], where v = v and b = b]
                apply (simp add: f drop_eq xbs_i upd_eq eq)
                done
            qed
          }
          with not_is_padding_j
          have "¬ padding_base.is_padding_byte
                    (component_access_struct (TypAggregate (f # fs')))
                    (component_update_struct (TypAggregate (f # fs')))
                    (foldl (+) 0 (map (field_sz  dt_trd) (f # fs'))) i" by blast
          ultimately show ?thesis by blast
        qed
      qed
    qed

    then show ?thesis
      by (simp add: TypDesc TypAggregate)
  qed
qed


theorem wf_field_desc_component_desc:
  assumes wf:"wf_field_descs (set (field_descs t))"
  assumes ind: "field_descs_independent (toplevel_field_descs t)"
  shows "wf_field_desc (component_desc t)"
  apply (unfold_locales)
        apply (rule component_complement_padding [OF wf ind], assumption)
       apply (rule component_double_update [OF wf ind])
      apply (rule component_access_update [OF wf ind])
     apply (rule component_update_access [OF wf])
    apply (rule component_access_size [OF wf])
   apply (rule component_access_result_size [OF wf])
  apply (rule ext, rule component_update_size [OF wf])
  done



(* fixme: move up *)
lemma field_desc_list_append [simp]: "field_descs_list (fs1 @ fs2) = field_descs_list fs1 @ field_descs_list fs2"
  by (induct fs1 arbitrary: fs2) auto

(* fixme: move up *)
lemma toplevel_field_desc_list_append [simp]:
"toplevel_field_descs_list (fs1 @ fs2) = toplevel_field_descs_list fs1 @ toplevel_field_descs_list fs2"
  by (induct fs1 arbitrary: fs2) auto

corollary wf_field_descs_struct_append_first:
  assumes wf:"wf_field_descs (set (field_descs_struct (TypAggregate (fs1 @ fs2))))"
  assumes ind: "field_descs_independent (toplevel_field_descs_struct (TypAggregate (fs1 @ fs2)))"
  shows "wf_field_desc (component_desc_struct (TypAggregate fs1))"
proof -
  fix algn
  from wf have wf': "wf_field_descs (set (field_descs (TypDesc algn (TypAggregate fs1) [])))"
    by simp
  from ind
  have ind': "field_descs_independent (toplevel_field_descs (TypDesc algn (TypAggregate fs1) []))"
    by (simp add: field_descs_independent_append_first)
  from wf_field_desc_component_desc [OF wf' ind']
  show ?thesis
    by simp
qed

corollary wf_field_descs_struct_append_second:
  assumes wf:"wf_field_descs (set (field_descs_struct (TypAggregate (fs1 @ fs2))))"
  assumes ind: "field_descs_independent (toplevel_field_descs_struct (TypAggregate (fs1 @ fs2)))"
  shows "wf_field_desc (component_desc_struct (TypAggregate fs2))"
proof -
  fix algn
  from wf have wf': "wf_field_descs (set (field_descs (TypDesc algn (TypAggregate fs2) [])))"
    by simp
  from ind
  have ind': "field_descs_independent (toplevel_field_descs (TypDesc algn (TypAggregate fs2) []))"
    by (simp add: field_descs_independent_append_second)
  from wf_field_desc_component_desc [OF wf' ind']
  show ?thesis
    by simp
qed


corollary wf_field_descs_component_desc:
  assumes wf:"wf_field_descs (set (field_descs t))"
  assumes ind: "field_descs_independent (toplevel_field_descs t)"
  shows "wf_field_descs (insert (component_desc t) (set (field_descs t)))"
  using wf_field_desc_component_desc [OF wf ind] wf
  by simp

lemma size_td_field_sz:
  fixes
    t::"'a xtyp_info" and
    st::"'a xtyp_info_struct" and
    fs::"'a xtyp_info_tuple list" and
    f::"'a xtyp_info_tuple"
  shows
 "wf_component_descs t  size_td t = field_sz (component_desc t)"
 "wf_component_descs_struct st  size_td_struct st = field_sz (component_desc_struct st)"
 "wf_component_descs_list fs  size_td_list fs = field_sz (component_desc_struct (TypAggregate fs))"
 "wf_component_descs_tuple f  size_td_tuple f = field_sz (dt_trd f)"
proof (induct t and st and fs and f)
  case (Cons_typ_desc dt_tuple list)
  then show ?case 
    apply (cases dt_tuple)
    apply (clarsimp simp add: sum_nat_foldl)
    done
qed auto


(* fixme unused? *)
lemma (in c_type) simple_type_to_xto_eq:
  fixes v::"'a"
  assumes simple: "¬ aggregate (typ_info_t TYPE('a))"
  shows "to_bytes v = xto_bytes v"
proof -
  from simple_type_dest [OF simple]
  show ?thesis
    by (clarsimp simp add: xto_bytes_def to_bytes_def)
qed


(* fixme move up *)
lemma field_desc_independent_empty [simp]: "field_desc_independent acc upd {}"
  by (simp add: field_desc_independent_def)


lemma component_descs_field_descs_independent:
 "component_descs_independent t  field_descs_independent (toplevel_field_descs t)"
  apply (cases t)
  subgoal for x1 st nm
    apply (cases st)
     apply (simp )
    subgoal for fs
      apply (cases fs)
       apply simp
      apply simp
      done
    done
  done

lemma component_descs_list_field_descs_independent:
 "component_descs_independent_list fs  field_descs_independent (toplevel_field_descs_list fs)"
   apply (cases fs)
   apply simp
  apply simp
  done


theorem access_ti_component_desc_compatible:
  "bs v::'a. wf_component_descs t; component_descs_independent t;
    wf_field_descs (set (field_descs t))
    access_ti t v bs = field_access (component_desc t) v bs"
  "bs v::'a. wf_component_descs_struct st; component_descs_independent_struct st;
    wf_field_descs (set (field_descs_struct st))
    access_ti_struct st v bs = field_access (component_desc_struct st) v bs"
  "bs v::'a. wf_component_descs_list fs; component_descs_independent_list fs;
    wf_field_descs (set (field_descs_list fs))
    access_ti_list fs v bs = field_access (component_desc_struct (TypAggregate fs)) v bs"
  "bs v::'a. wf_component_descs_tuple f; component_descs_independent_tuple f;
    wf_field_descs (set (field_descs (dt_fst f)))
    access_ti_tuple f v bs = field_access (dt_trd f) v bs"
proof (induct t and st and fs and f (*arbitrary: bs v*)) (* fixme: figure out why arbitrary bs v does not work *)
  case (TypDesc algn st n)
  then show ?case by simp
next
  case (TypScalar sz align d)
  then show ?case by simp
next
  case (TypAggregate fs)
  then show ?case by simp
next
  case Nil_typ_desc
  then show ?case by simp
next
  case (Cons_typ_desc f fs')
  obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

  from Cons_typ_desc.prems obtain
     wf_descs_f: "wf_component_descs_tuple f" and wf_descs_fs': "wf_component_descs_list fs'" and
     ind: "field_descs_independent (toplevel_field_descs_tuple f @ toplevel_field_descs_list fs')" and
     ind_cf: "component_descs_independent_tuple f" and
     ind_cfs': "component_descs_independent_list fs'" and
     wf_field_desc_f: "wf_field_descs (set (field_descs (dt_fst f)))" and
     wf_d: "wf_field_desc d" and wf_ft: "wf_field_descs (set (field_descs ft))" and
     wf_field_descs_fs': "wf_field_descs (set (field_descs_list fs'))"
    by (auto simp add: f)


  note ind_fs' = field_descs_independent_append_second [OF ind]

  from wf_d interpret wf_d: wf_field_desc d.


  have wf_fd_fs': "wf_field_descs (insert (component_desc_struct (TypAggregate fs'))
          (set (field_descs_list fs')))"
  proof -
    fix algn
    from wf_field_descs_fs'
    have wf:"wf_field_descs (set (field_descs (TypDesc algn (TypAggregate fs') [])))"
      by simp
    from ind_fs'
    have ind: "field_descs_independent (toplevel_field_descs (TypDesc algn (TypAggregate fs') []))"
      by simp
    from wf_field_descs_component_desc [OF wf ind] show ?thesis
      by simp
  qed


  from Cons_typ_desc.hyps(1) [OF wf_descs_f ind_cf wf_field_desc_f ]
  have eq_f: "access_ti_tuple f v (take (size_td ft) bs) =
              field_access (dt_trd f) v (take (size_td ft) bs)".
  from Cons_typ_desc.hyps(2) [OF wf_descs_fs' ind_cfs' wf_field_descs_fs' ]
  have eq_fs': "access_ti_list fs' v (drop (size_td ft) bs) =
                 field_access (component_desc_struct (TypAggregate fs')) v
                 (drop (size_td ft) bs)" .

  from wf_descs_f have sz_eq: "field_sz d = size_td ft" by (simp add: f size_td_field_sz)


  from sz_eq wf_d.access_size
  have eq_access_take: "field_access d v (take (size_td ft) bs) = field_access d v bs"
    by (simp )

  from wf_descs_f have sz_eq: "field_sz d = size_td ft" by (simp add: f size_td_field_sz)

  from eq_f eq_fs' eq_access_take
    show ?case by (simp add: f wf_d.access_result_size size_td_field_sz sz_eq)
next
  case (DTuple_typ_desc ft fn d)
  from DTuple_typ_desc.prems obtain
    d: "d = component_desc ft" and
    wf_ft: "wf_component_descs ft" and
    ind_cf: "component_descs_independent ft" and
    wf_descs_ft: "wf_field_descs (set (field_descs ft))"
    by auto

  from wf_field_descs_component_desc [OF wf_descs_ft] ind_cf
  have wf_desc_ft: "wf_field_desc (component_desc ft)"
    by (auto intro: component_descs_field_descs_independent)
  from component_descs_field_descs_independent [OF ind_cf]
  have "field_descs_independent (toplevel_field_descs ft)" .

  from DTuple_typ_desc.hyps [OF wf_ft ind_cf wf_descs_ft ]

  show ?case by (simp add: d)
qed

theorem update_ti_component_desc_compatible:
  "bs v::'a. wf_component_descs t; component_descs_independent t;
    wf_field_descs (set (field_descs t))
    update_ti t bs v = field_update (component_desc t) bs v"
  "bs v::'a. wf_component_descs_struct st; component_descs_independent_struct st;
    wf_field_descs (set (field_descs_struct st))
    update_ti_struct st bs v = field_update (component_desc_struct st) bs v"
  "bs v::'a. wf_component_descs_list fs; component_descs_independent_list fs;
    wf_field_descs (set (field_descs_list fs))
    update_ti_list fs bs v = field_update (component_desc_struct (TypAggregate fs)) bs v"
  "bs v::'a. wf_component_descs_tuple f; component_descs_independent_tuple f;
    wf_field_descs (set (field_descs (dt_fst f)))
    update_ti_tuple f bs v = field_update (dt_trd f) bs v"
proof (induct t and st and fs and f (*arbitrary: bs v*)) (* fixme: figure out why arbitrary bs v does not work *)
  case (TypDesc algn st n)
  then show ?case by simp
next
  case (TypScalar sz align d)
  then show ?case by simp
next
  case (TypAggregate fs)
  then show ?case by simp
next
  case Nil_typ_desc
  then show ?case by simp
next
  case (Cons_typ_desc f fs')
  obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

  from Cons_typ_desc.prems obtain
     wf_descs_f: "wf_component_descs_tuple f" and wf_descs_fs': "wf_component_descs_list fs'" and
     ind: "field_descs_independent (toplevel_field_descs_tuple f @ toplevel_field_descs_list fs')" and
     ind_cf: "component_descs_independent_tuple f" and
     ind_cfs': "component_descs_independent_list fs'" and
     ind_d: "field_desc_independent (field_access d) (field_update d) (set (toplevel_field_descs_list fs'))" and
     wf_field_desc_f: "wf_field_descs (set (field_descs (dt_fst f)))" and
     wf_d: "wf_field_desc d" and wf_ft: "wf_field_descs (set (field_descs ft))" and
     wf_field_descs_fs': "wf_field_descs (set (field_descs_list fs'))"
    by (auto simp add: f)


  note ind_fs' = field_descs_independent_append_second [OF ind]

  from wf_d interpret wf_d: wf_field_desc d.

  from Cons_typ_desc.hyps(2) [OF wf_descs_fs' ind_cfs' wf_field_descs_fs' ]
  have eq_fs': "update_ti_list fs' (drop (size_td ft) bs) v =
         fst (apply_field_updates (map dt_trd fs') (drop (size_td ft) bs) v)" (is "?upd_ti_fs' = ?upd_fs'")
    by simp

  from Cons_typ_desc.hyps(1) [OF wf_descs_f ind_cf wf_field_desc_f ]
  have eq_f: "update_ti ft (take (size_td ft) bs) ?upd_ti_fs' =
                field_update d (take (size_td ft) bs) ?upd_fs'" by (simp add: f eq_fs')
  also
  from field_update_apply_field_updates_commute [OF ind_d ind_fs', where bs= "(take (size_td ft) bs)" and bs'="(drop (size_td ft) bs)"]
  have " = fst (apply_field_updates (toplevel_field_descs_list fs') (drop (size_td ft) bs)
                (field_update d (take (size_td ft) bs) v))"
    by (simp add: toplevel_field_descs_list_map)
  finally have eq_ft: "update_ti ft (take (size_td ft) bs) ?upd_ti_fs' =
    fst (apply_field_updates (toplevel_field_descs_list fs') (drop (size_td ft) bs)
          (field_update d (take (size_td ft) bs) v))" .

  from size_td_field_sz(1) [of ft] wf_descs_f
  have sz_d: "field_sz d = size_td ft"
    by (simp add: f)


  show ?case
    apply (simp add: f )
    apply (simp add: eq_ft toplevel_field_descs_list_map wf_d.update_size [simplified sz_d] sz_d)
    done
next
  case (DTuple_typ_desc ft fn d)
  then show ?case by simp
qed


context xmem_type
begin


lemma wf_field_desc_component_desc: "wf_field_desc (component_desc (typ_info_t (TYPE('a))))"
  using wf_field_descs component_descs_independent
  by (auto intro: wf_field_desc_component_desc component_descs_field_descs_independent)

lemma wf_field_descs': "wf_field_descs (insert (component_desc (typ_info_t (TYPE('a))))
                            (set (field_descs (typ_info_t (TYPE('a))))))"
  using wf_field_descs
  by (auto intro: wf_field_desc_component_desc)

lemma wf_field_desc_t: "wf_field_desc (component_desc (typ_info_t (TYPE('a))))"
  using wf_field_descs' by (simp)

sublocale xmem_type_wf_field_desc: wf_field_desc "component_desc (typ_info_t (TYPE('a)))"
  by (rule wf_field_desc_t)

lemma xfrom_bytes_xto_bytes_inv: "xfrom_bytes (xto_bytes (v::'a) bs) = v"
proof -
  define t where "t = (typ_info_t TYPE('a))"
  have wf_comp_descs_t: "wf_component_descs t" by (simp add: wf_component_descs t_def)
  have ind_t: "component_descs_independent t" by (simp add: component_descs_independent t_def)
  from wf_field_descs
  have wf_field_descs_t: "wf_field_descs (set (field_descs t))"
    by (simp add: t_def)
  have xto: "xto_bytes v bs = field_access (component_desc t) v bs" (is "(_ = ?acc)")
    by (simp add: xto_bytes_def t_def)

  from wf_field_desc_component_desc have "wf_field_desc (component_desc t)" by (simp add: t_def)
  then interpret wf_t: wf_field_desc "component_desc t".
  from wf_t.access_result_size
  have len_acc: "length ?acc = field_sz (component_desc t)" .
  from size_td_field_sz(1) [OF wf_comp_descs_t]
  have size_t: "size_td t = field_sz (component_desc t)".
  have len_acc': "size_td t = length ?acc" by (simp add: len_acc size_t)
  from size_t len_acc
  have len_acc'': "length ?acc = size_of TYPE('a)" by (simp add: size_of_def t_def)
  from len_acc'' len_acc'
  have len_acc''': "size_of TYPE('a) = size_td (typ_info_t TYPE('a))" by (simp add: t_def)

  from update_ti_component_desc_compatible(1) [OF wf_comp_descs_t ind_t wf_field_descs_t ]
  have "field_update (component_desc t) (field_access (component_desc t) v bs) undefined =
        update_ti t (field_access (component_desc t) v bs) undefined" by simp
  also
  from upd [rule_format, OF len_acc'', folded t_def, where v= undefined and w = v] len_acc' t_def
  have " = update_ti t (field_access (component_desc t) v bs) v" by (simp add: update_ti_t_def)
  also
  from update_ti_component_desc_compatible(1) [OF wf_comp_descs_t ind_t wf_field_descs_t ]
  have " = field_update (component_desc t) (field_access (component_desc t) v bs) v" .
  also
  from wf_t.update_access
  have " = v" .
  finally
  have "field_update (component_desc t) (field_access (component_desc t) v bs) undefined = v" .

  with len_acc show ?thesis
    by (simp add: xto xfrom_bytes_def t_def)
qed

lemma xto_bytes_inj:
  "xto_bytes (v::'a) = xto_bytes (v'::'a)  v = v'"
  apply (drule fun_cong [where x="replicate (size_of TYPE('a)) 0"])
  apply (drule arg_cong [where f="xfrom_bytes::byte list  'a"])
  apply (simp add: xfrom_bytes_xto_bytes_inv)
  done

lemma field_update_update_ti_t:
  assumes len: "length bs = size_td (typ_info_t (TYPE('a)))"
  shows "field_update (component_desc (typ_info_t (TYPE('a)))) bs = update_ti_t (typ_info_t (TYPE('a))) bs"
proof -
  from len
    update_ti_component_desc_compatible(1) [OF wf_component_descs component_descs_independent
      wf_field_descs]
  show ?thesis
    by (simp add: update_ti_t_def fun_eq_iff)
qed

lemma field_update_update_ti:
  shows "field_update (component_desc (typ_info_t (TYPE('a)))) = update_ti (typ_info_t (TYPE('a)))"
proof -
  from
    update_ti_component_desc_compatible(1) [OF wf_component_descs component_descs_independent
      wf_field_descs]
  show ?thesis
    by (simp add: fun_eq_iff)
qed

lemma field_access_access_ti:
  shows "field_access (component_desc (typ_info_t (TYPE('a)))) = access_ti (typ_info_t (TYPE('a))) "
proof -
  from
    access_ti_component_desc_compatible(1) [OF wf_component_descs component_descs_independent
      wf_field_descs]
  show ?thesis
    by (simp add: fun_eq_iff)
qed

lemma field_sz_size_td:
  "field_sz (component_desc (typ_info_t (TYPE('a)))) = size_td (typ_info_t (TYPE('a)))"
  by (simp add: local.wf_component_descs size_td_field_sz(1))

lemma field_sz_size_of:
  "field_sz (component_desc (typ_info_t (TYPE('a)))) = size_of (TYPE('a))"
  by (simp add: size_of_def field_sz_size_td)



lemma xto_bytes_size: "xto_bytes (v::'a) (take (size_td (typ_info_t TYPE('a))) bs) = xto_bytes v bs"
proof -
  from xmem_type_wf_field_desc.access_size size_td_field_sz(1) [OF wf_component_descs]
  show ?thesis
  by (simp add: xto_bytes_def)
qed

lemma xto_bytes_result_size: "length (xto_bytes (v::'a) bs) = size_td (typ_info_t TYPE('a))"
proof -
  from xmem_type_wf_field_desc.access_result_size size_td_field_sz(1) [OF wf_component_descs]
  show ?thesis
  by (simp add: xto_bytes_def)
qed


lemma xfrom_bytes_size: "(xfrom_bytes::byte list  'a) (take (size_td (typ_info_t TYPE('a))) bs) = xfrom_bytes bs"
proof -
  from xmem_type_wf_field_desc.update_size [where bs=bs] size_td_field_sz(1) [OF wf_component_descs]
  show ?thesis
    by (simp add: xfrom_bytes_def)
qed

lemma entire_update:
  shows "field_update (component_desc (typ_info_t (TYPE('a)))) bs v = field_update (component_desc (typ_info_t (TYPE('a)))) bs w"
    by (metis xmem_type_wf_field_desc.double_update xfrom_bytes_def xfrom_bytes_xto_bytes_inv)

lemma update_access_complete:
  shows "field_update (component_desc (typ_info_t (TYPE('a)))) (field_access (component_desc (typ_info_t (TYPE('a)))) v bs) w = v"
  by (metis entire_update xmem_type_wf_field_desc.update_access)


end


lemma contained_field_descs_list_all: "contained_field_descs_list xs = list_all contained_field_descs_tuple xs"
  by (induct xs) auto


lemma toplevel_field_descs_map:
  "toplevel_field_descs (map_td (λ_ _. update_desc acc upd) (update_desc acc upd) t) =
     map (update_desc acc upd) (toplevel_field_descs t)"
  "toplevel_field_descs_struct (map_td_struct (λ_ _. update_desc acc upd) (update_desc acc upd) st) =
     map (update_desc acc upd) (toplevel_field_descs_struct st)"
  "toplevel_field_descs_list (map_td_list (λ_ _. update_desc acc upd) (update_desc acc upd) fs) =
     map (update_desc acc upd) (toplevel_field_descs_list fs)"
  "toplevel_field_descs_tuple (map_td_tuple (λ_ _. update_desc acc upd) (update_desc acc upd) f) =
     map (update_desc acc upd) (toplevel_field_descs_tuple f)"
     by (induct t and st and fs and f) auto

lemma toplevel_field_descs_adjust_ti: "toplevel_field_descs (adjust_ti t acc upd) = map (update_desc acc upd) (toplevel_field_descs t)"
  by (simp add: adjust_ti_def toplevel_field_descs_map)

theorem contained_field_descs_empty_typ_info [simp]: "contained_field_descs (empty_typ_info algn n)"
  by (simp add: empty_typ_info_def)

lemma fields_contained_update_desc:
  assumes contained_t: "fields_contained (field_access d) (field_update d) (set (toplevel_field_descs t))"
  shows "fields_contained (field_access (update_desc acc upd d))
     (field_update (update_desc acc upd d))
     (update_desc acc upd ` set (toplevel_field_descs t))"
proof (rule fields_contained.intro)
  fix d' s s'
  assume d'_in: "d'  update_desc acc upd ` set (toplevel_field_descs t)"
  assume acc_contained: "field_access (update_desc acc upd d) s =
       field_access (update_desc acc upd d) s'"

  interpret ft: fields_contained "(field_access d)" "(field_update d)" "set (toplevel_field_descs t)"
    by (rule contained_t)

  from acc_contained have acc: "field_access d (acc s) = field_access d (acc s')"
    by (simp add: update_desc_def)

  from d'_in obtain d'' where
    d''_in: "d''  set (toplevel_field_descs t)" and
    d': "d' = update_desc acc upd d''"
    by auto

  from ft.access_contained [OF d''_in acc]
  have "field_access d'' (acc s) = field_access d'' (acc s')".
  with d'
  show "field_access d' s = field_access d' s'"
    by (simp add: update_desc_def)
next
  fix d' bs s
  assume d'_in: "d'  update_desc acc upd ` set (toplevel_field_descs t)"

  interpret ft: fields_contained "(field_access d)" "(field_update d)" "set (toplevel_field_descs t)"
    by (rule contained_t)

  from d'_in obtain d'' where
    d''_in: "d''  set (toplevel_field_descs t)" and
    d': "d' = update_desc acc upd d''"
    by auto
  from ft.update_contained [OF d''_in ]
  obtain bs' where cont: "s'. field_access d (acc s') = field_access d (acc s) 
                              field_update d'' bs (acc s') = field_update d bs' (acc s')"
    by fastforce

  from cont
  show "bs'.  s'. field_access (update_desc acc upd d) s' =
                    field_access (update_desc acc upd d) s  field_update d' bs s' =
             field_update (update_desc acc upd d) bs' s'"
    by (auto simp add: update_desc_def d')
qed



lemma contained_field_descs_update_desc:
  "contained_field_descs t 
     contained_field_descs (map_td (λ_ _. update_desc acc upd) (update_desc acc upd) t)"
  "contained_field_descs_struct st 
     contained_field_descs_struct (map_td_struct (λ_ _. update_desc acc upd) (update_desc acc upd) st)"
  "contained_field_descs_list fs 
     contained_field_descs_list (map_td_list (λ_ _. update_desc acc upd) (update_desc acc upd) fs)"
  "contained_field_descs_tuple f 
     contained_field_descs_tuple (map_td_tuple (λ_ _. update_desc acc upd) (update_desc acc upd) f)"
proof (induct t and st and fs and f)
  case (TypDesc st n)
  then show ?case by simp
next
  case (TypScalar n sz d)
  then show ?case by simp
next
  case (TypAggregate fs)
  then show ?case by simp
next
  case Nil_typ_desc
  then show ?case by simp
next
  case (Cons_typ_desc f fs)
  then show ?case by simp
next
  case (DTuple_typ_desc ft fn d)
  note contained_field_descs_tuple (DTuple ft fn d)
  then obtain
    contained_ft: "contained_field_descs ft" and
    fields_contained_ft: "fields_contained (field_access d) (field_update d) (set (toplevel_field_descs ft))"
    by simp
  from contained_ft DTuple_typ_desc(1)
  have contained_map: "contained_field_descs
     (map_td (λ_ _. update_desc acc upd) (update_desc acc upd) ft)"
    by simp

  from fields_contained_update_desc [OF fields_contained_ft]
  have "fields_contained (field_access (update_desc acc upd d))
     (field_update (update_desc acc upd d))
     (update_desc acc upd ` set (toplevel_field_descs ft))" .

  then have "fields_contained (field_access (update_desc acc upd d))
          (field_update (update_desc acc upd d))
          (set (toplevel_field_descs (map_td (λ_ _. update_desc acc upd) (update_desc acc upd) ft)))"
    by (simp add: toplevel_field_descs_map)
  with DTuple_typ_desc show ?case by simp
qed

theorem contained_field_descs_adjust_ti:
  fixes t::"'a xtyp_info"
  assumes contained_t: "contained_field_descs t"
  shows "contained_field_descs (adjust_ti t acc upd)"
  using contained_field_descs_update_desc(1) [OF contained_t]
  by (simp add: adjust_ti_def)

theorem contained_field_descs_extend_ti:
  assumes contained_t: "contained_field_descs t"
  assumes contained_ft: "contained_field_descs ft"
  assumes fields_contained_ft: "fields_contained (field_access d) (field_update d) (set (toplevel_field_descs ft))"
  shows "contained_field_descs (extend_ti t ft algn n d)"
  using contained_t contained_ft fields_contained_ft
  apply (cases t)
  subgoal for x1 x2 x3
    apply  simp
    apply (cases x2)
     apply simp
    apply (simp add: contained_field_descs_list_all)
    done
  done

theorem contained_field_descs_ti_pad_combine:
  fixes t::"'a xtyp_info"
  assumes cont_t: "contained_field_descs t"
  shows "contained_field_descs (ti_pad_combine n t)"
proof -
  define d::"'a field_desc" where
   "d  field_access = λv bs. if n  length bs then take n bs else replicate n 0,
         field_update = λbs. id, field_sz = n"
  define ft::"'a xtyp_info" where "ft  TypDesc 0 (TypScalar n 0 d) ''!pad_typ''"
  define fn where "fn  (foldl (@) ''!pad_'' (field_names_list t))"
  have "contained_field_descs (extend_ti t ft 0 fn d )"
    by (rule contained_field_descs_extend_ti [OF cont_t]) (auto simp add: ft_def d_def fields_contained_def)

  then show ?thesis
    by (simp add: ti_pad_combine_def Let_def d_def ft_def fn_def padding_desc_def)
qed

lemma contained_field_descs_simp[simp]:
 "contained_field_descs (map_align f t) = contained_field_descs t"
  by (cases t) (simp)

theorem contained_field_descs_final_pad:
  fixes t::"'a xtyp_info"
  assumes cont_t: "contained_field_descs t"
  shows "contained_field_descs (final_pad algn t)"
  using cont_t
  by (simp add: final_pad_def contained_field_descs_ti_pad_combine Let_def)

lemma (in xmem_type) fields_contained_update_desc_mem_type:
  fixes acc:: "'b  'a"
  fixes D:: "'a field_desc set"
  shows "fields_contained (xto_bytes  acc) (upd  xfrom_bytes) (update_desc acc upd ` D)"
proof (rule fields_contained.intro)
  fix d s s'
  assume d_in: "d  update_desc acc upd ` D"
  assume to_btyes_eq: "(xto_bytes  acc) s = (xto_bytes  acc) s'"

  hence "acc s = acc s'"
    by (auto intro: xto_bytes_inj)

  with d_in
  show "field_access d s = field_access d s'"
    by (auto simp add: update_desc_def)
next
  fix d bs s
  assume d_in: "d  update_desc acc upd ` D"

  from d_in obtain d' where d'_in: "d'  D" and d: "d = update_desc acc upd d'"
    by auto

  define x where "x  λs. field_update d' bs (acc s)"


  from xfrom_bytes_xto_bytes_inv obtain bs' where
   cont: "s'. acc s' = acc s  xfrom_bytes (xto_bytes (x s') bs') = (x s')"
    by auto


  from  d'_in cont
  show "bs'.  s'. (xto_bytes  acc) s' = (xto_bytes  acc) s 
    field_update d bs s' = (upd  xfrom_bytes) bs' s'"
    by (metis (no_types, lifting) comp_apply d field_desc.simps(2) update_desc_def x_def xto_bytes_inj)
qed





locale wf_field =
  fixes acc::"'s  'a"
  fixes upd::"'a  's  's"
  assumes double_update_upd: "v w s. upd v (upd w s) = upd v s"
  assumes acc_upd: "v s. acc (upd v s) = v"
  assumes upd_acc: "s. upd (acc s) s = s"

locale wf_cfield = wf_field +
  constrains acc::"'s  'a::c_type"
locale wf_xfield = wf_cfield +
  constrains acc::"'s  'a::xmem_type"

lemma (in wf_field) wf_field_descs_adjust_ti:
  assumes wf_t: "wf_field_descs (set (field_descs t))"
  shows "wf_field_descs (set (field_descs (adjust_ti t acc upd)))"
proof -
  have "wf_field_descs (update_desc acc upd ` set (field_descs t))"
  proof (rule wf_field_descs.intro)
    fix d
    assume "d  update_desc acc upd ` set (field_descs t)"
    then obtain d' where d'_in: "d'  set (field_descs t)" and d: "d = update_desc acc upd d'"
      by auto
    from wf_t d'_in have "wf_field_desc d'"
      by (rule wf_field_descs.wf_desc)
    then interpret wf_d': wf_field_desc "d'" .
    from wf_d'.wf_field_desc_update_desc [of upd acc, OF double_update_upd acc_upd upd_acc]
    have "wf_field_desc (update_desc acc upd d')" .
    then
    show "wf_field_desc d"
      by (simp add: d)
  qed
  then show ?thesis
    by (simp add: adjust_ti_def field_descs_map)
qed



lemma field_descs_list_append [simp]: "field_descs_list (fs @ fs') = field_descs_list fs @ field_descs_list fs'"
  by (induct fs arbitrary: fs') auto

lemma wf_field_descs_extend_ti:
  assumes wf_t: "wf_field_descs (set (field_descs t))"
  assumes wf_ft: "wf_field_descs (set (field_descs ft))"
  assumes wf_d: "wf_field_desc d"
  shows "wf_field_descs (set (field_descs (extend_ti t ft algn fn d)))"
proof (cases t)
  case (TypDesc algn st n)
  note desc = this
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    with wf_ft wf_d show ?thesis
      by (simp add: desc)
  next
    case (TypAggregate fs)
    note aggr = this
    show ?thesis
    proof (cases fs)
      case Nil
      then show ?thesis
        using wf_ft wf_d by (simp add: desc aggr)
    next
      case (Cons f fs')
      note cons = this
      obtain ft' fn fd where f: "f = DTuple ft' fn fd" by (cases f)
      show ?thesis
        using wf_ft wf_t wf_d by (auto simp add: desc aggr cons f wf_field_descs_def)
    qed
  qed
qed


lemma padding_pad: "complement_padding (λv bs. if n  length bs then take n bs else replicate n 0) (λbs. id) n"
  apply (unfold_locales)
  by (auto simp add: padding_base.is_padding_byte_def padding_base.is_value_byte_def) 
     (metis (mono_tags, opaque_lifting) Ex_list_of_length len8 len_not_eq_0
      less_irrefl neq0_conv nth_list_update_eq word_power_less_1)




lemma wf_field_desc_pad:
"wf_field_desc
     field_access = λv bs. if n  length bs then take n bs else replicate n 0,
      field_update = λbs. id, field_sz = n"
  apply (intro_locales)
   apply simp
  apply (rule padding_pad)
  apply (unfold_locales)
       apply auto
  done

lemma wf_field_descs_ti_pad_combine: "wf_field_descs (set (field_descs t)) 
    wf_field_descs (set (field_descs (ti_pad_combine n t)))"
  apply (simp add: ti_pad_combine_def Let_def)
  apply (rule wf_field_descs_extend_ti)
    apply (auto simp add: wf_field_desc_pad padding_desc_def)
  done

lemma set_field_descs_map_align[simp]: "set (field_descs (map_align f t)) = set (field_descs t)"
  by (cases t) simp

lemma wf_field_descs_final_pad: "wf_field_descs (set (field_descs t)) 
  wf_field_descs (set (field_descs (final_pad algn t)))"
  apply (clarsimp simp add: final_pad_def Let_def)
  apply (rule wf_field_descs_ti_pad_combine)
  apply simp
  done


lemma (in wf_xfield) padding_lift:
shows "complement_padding (xto_bytes  acc) (upd  xfrom_bytes) (size_of TYPE('a))"
proof -
(* FIXME: remove
  have "wf_field_desc (component_desc (typ_info_t TYPE('a)))"
    using xmem_type_class.wf_field_desc_component_desc by blast
  then interpret wf_field_desc "(component_desc (typ_info_t TYPE('a)))" .
*)
  thm xmem_type_wf_field_desc.access_update
  thm xmem_type_wf_field_desc.is_padding_byte_acc_upd_compose
  show ?thesis
  proof
    fix i
    assume i_bound: "i < size_of TYPE('a)"

    {
      fix bs v
      have "upd (field_update (component_desc (typ_info_t TYPE('a))) bs (acc v)) v =
         upd (field_update (component_desc (typ_info_t TYPE('a))) bs undefined) v"
        by (simp add: entire_update [where bs = bs and v = "acc v" and w = undefined])
    } note tweak_eq = this

    have sz_eq: "field_sz (component_desc (typ_info_t TYPE('a))) = size_of TYPE('a)"
      by (simp add: size_of_def size_td_field_sz(1) wf_component_descs)

    from  xmem_type_wf_field_desc.is_padding_byte_acc_upd_compose [where acc=acc and upd=upd, OF acc_upd, of i]
       xmem_type_wf_field_desc.is_value_byte_acc_upd_compose [where acc=acc and upd=upd, OF acc_upd, of i]
    show "padding_base.is_padding_byte (xto_bytes  acc) (upd  xfrom_bytes)
          (size_of TYPE('a)) i 
         padding_base.is_value_byte (xto_bytes  acc) (upd  xfrom_bytes)
          (size_of TYPE('a)) i"
      apply (simp add: xto_bytes_def xfrom_bytes_def [abs_def] comp_def tweak_eq sz_eq)
      using  xmem_type_wf_field_desc.complement i_bound sz_eq
        by metis
  qed
qed



(* move up *)
lemma (in wf_xfield) wf_field_desc_lift:
  shows "wf_field_desc field_access = xto_bytes  acc,
         field_update = upd  xfrom_bytes,
         field_sz = size_of (TYPE('a))" (is "wf_field_desc ?lift")
  apply (intro_locales, simp, rule padding_lift, unfold_locales)
proof -
  fix bs bs' s
  show "field_update ?lift bs (field_update ?lift bs' s) = field_update ?lift bs s"
    by (simp add: double_update_upd)
next
  fix bs s bs' s'
  show "field_access ?lift (field_update ?lift bs s) bs' = field_access ?lift (field_update ?lift bs s') bs'"
    by (simp add: acc_upd)
next
  fix s bs
  show "field_update ?lift (field_access ?lift s bs) s = s"
    by (simp add: upd_acc xfrom_bytes_xto_bytes_inv)
next
  fix s bs
  show "field_access ?lift s (take (field_sz ?lift) bs) = field_access ?lift s bs"
    by (simp add: xto_bytes_size size_of_def)
next
  fix s bs
  show "length (field_access ?lift s bs) = field_sz ?lift"
    by (simp add: xto_bytes_result_size size_of_def)
next
  fix bs
  show "field_update ?lift (take (field_sz ?lift) bs) = field_update ?lift bs"
    by (simp add: xfrom_bytes_size size_of_def)
qed



lemma (in wf_xfield) wf_field_descs_ti_typ_combine:
  assumes wf_ft: "wf_field_descs (set (field_descs ft))"
  shows "wf_field_descs (set (field_descs (ti_typ_combine (TYPE('a)) acc upd algn fn ft)))"
  apply (simp add: ti_typ_combine_def)
  apply (rule wf_field_descs_extend_ti)
    apply (rule wf_ft)
   apply (rule wf_field_descs_adjust_ti)
   apply (rule wf_field_descs)
  apply (rule wf_field_desc_lift)
  done


lemma (in wf_xfield) wf_field_descs_ti_typ_pad_combine:
  assumes wf_ft: "wf_field_descs (set (field_descs ft))"
  shows "wf_field_descs (set (field_descs (ti_typ_pad_combine (TYPE('a)) acc upd algn fn ft)))"
proof (cases "0 < padup (max (2 ^ algn) (align_of TYPE('a))) (size_td ft)")
  case True
  then show ?thesis
    apply (simp add: ti_typ_pad_combine_def Let_def)
    apply (rule wf_field_descs_ti_typ_combine)
    apply (rule wf_field_descs_ti_pad_combine)
    apply (rule wf_ft)
    done
next
  case False
  then show ?thesis
    apply (simp add: ti_typ_pad_combine_def Let_def)
    apply (rule wf_field_descs_ti_typ_combine)
    apply (rule wf_ft)
    done
qed

lemma wf_component_descs_empty_typ_info [simp]: "wf_component_descs (empty_typ_info algn n)"
  by (simp add: empty_typ_info_def)

lemma wf_component_descs_list_append [simp]:
  "wf_component_descs_list (fs @ fs') = (wf_component_descs_list fs  wf_component_descs_list fs')"
  by (induct fs arbitrary: fs') auto

lemma wf_component_descs_extend_ti:
  assumes wf_t: "wf_component_descs t"
  assumes wf_ft: "wf_component_descs ft"
  assumes d: "d = (component_desc ft)"
  shows "wf_component_descs (extend_ti t ft algn fn d)"
  apply (cases t)
  subgoal for x1 st n
    apply (cases st)
     apply (simp add: wf_ft d)
    subgoal for fs
      apply (cases fs)
       apply (simp add: wf_ft d)
      subgoal for f fs'
        apply (cases f)
        apply (insert wf_t)
        apply (simp add: d wf_ft)
        done
      done
    done
  done

lemma wf_component_descs_ti_pad_combine:
  assumes wf_t: "wf_component_descs t"
  shows "wf_component_descs (ti_pad_combine n t)"
  apply (simp add: ti_pad_combine_def Let_def padding_desc_def)
  apply (rule wf_component_descs_extend_ti)
    apply (rule wf_t)
   apply simp
  apply simp
  done


lemma wf_component_descs_map_align [simp]: "wf_component_descs (map_align f t) = wf_component_descs t"
  by (cases t) simp

lemma wf_component_descs_final_pad:
  assumes wf_t: "wf_component_descs t"
  shows "wf_component_descs (final_pad algn t)"
  by (clarsimp simp add: final_pad_def Let_def wf_t wf_component_descs_ti_pad_combine)

lemma field_sz_update_desc [simp]: "field_sz (update_desc acc upd d) = field_sz d"
  by (simp add: update_desc_def)



lemma component_sz_struct_update_desc_commutes:
"(component_sz_struct (TypAggregate fs)) =
      component_sz_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) (TypAggregate fs))"
proof (induct fs)
  case Nil
  then show ?case by simp
next
  case (Cons f fs')
  obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp
  have map_eq: "map (field_sz  dt_trd) (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs') =
        map (field_sz  dt_trd) fs'"
    apply (induct fs')
     apply simp
    subgoal for f' fs''
    apply (cases f')
    apply clarsimp
      done
    done
  show ?case by (simp add: f map_eq)
qed

lemma component_access_struct_update_desc_commutes':
"component_access_struct (TypAggregate fs) (acc v) bs =
      component_access_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) (TypAggregate fs)) v bs"
proof (induct fs arbitrary: bs)
  case Nil
  then show ?case by simp
next
  case (Cons f fs')
  obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

  have d_commutes: "field_access (update_desc acc upd d) v bs = field_access d (acc v) bs"
    by (simp add: update_desc_def)

  note hyp = Cons.hyps [where bs="(drop (length (field_access d (acc v) bs)) bs)" ]
  then
  show ?case
    by (simp add: f d_commutes hyp)
qed


lemma component_access_struct_update_desc_commutes:
"(component_access_struct (TypAggregate fs))  acc =
      component_access_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) (TypAggregate fs))"
  apply -
  apply (rule ext)
  apply (rule ext)
  apply (simp only: comp_def)
  apply (rule component_access_struct_update_desc_commutes')
  done

lemma (in wf_field) lemma_component_update_struct_update_desc_commutes:
  shows "upd (component_update_struct (TypAggregate fs) bs (acc v)) v =
          component_update_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) (TypAggregate fs)) bs v"
proof (induct fs arbitrary: v bs)
  case Nil
  then show ?case by (simp add: upd_acc)
next
  case (Cons f fs')
  obtain ft fn d where f: "f = DTuple ft fn d" by (cases f) simp

  have acc_update_desc: "acc (field_update (update_desc acc upd d) bs v) = field_update d bs (acc v)"
    by (simp add: update_desc_def acc_upd)

  have upd_eq: "upd (fst (apply_field_updates (map dt_trd fs') (drop (field_sz d) bs)
                 (field_update d bs (acc v)))) (field_update (update_desc acc upd d) bs v) =
               upd (fst (apply_field_updates (map dt_trd fs') (drop (field_sz d) bs)
               (field_update d bs (acc v)))) v"
    by (simp add: update_desc_def double_update_upd)


  note hyp = Cons.hyps [where bs = "(drop (field_sz d) bs)" and v="field_update (update_desc acc upd d) bs v"]

  from hyp
  show ?case
    by (simp add: f acc_update_desc upd_eq)
qed

lemma (in wf_field) update_desc_component_desc_struct_commutes:
  shows "update_desc acc upd (component_desc_struct (TypAggregate fs)) =
          component_desc_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) (TypAggregate fs))"
  using  lemma_component_update_struct_update_desc_commutes
   component_access_struct_update_desc_commutes [where acc=acc and upd=upd and fs=fs]
   component_sz_struct_update_desc_commutes  [where acc=acc and upd=upd  and fs=fs]
  apply (simp only: update_desc_def)
  apply (fastforce simp add: component_desc_struct_def)
  done

lemma (in wf_field) update_desc_component_desc_commutes:
  shows "update_desc acc upd (component_desc t) =
         component_desc (map_td (λn algn. update_desc acc upd) (update_desc acc upd) t)"
  using update_desc_component_desc_struct_commutes
  apply (cases t)
  apply simp
  subgoal for x1 st n
    apply (cases st)
     apply simp
    apply simp
    done
  done

lemma (in wf_field) wf_component_descs_map_td_update_desc:
  shows
  "wf_component_descs t
    wf_component_descs (map_td (λn algn. update_desc acc upd) (update_desc acc upd) t)"
  "wf_component_descs_struct st
   wf_component_descs_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st)"
  "wf_component_descs_list fs
   wf_component_descs_list (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs)"
  "wf_component_descs_tuple f
   wf_component_descs_tuple (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) f)"
     apply (induct t and st and fs and f)
       apply (auto simp add: update_desc_component_desc_commutes )
  done

lemma (in wf_field) wf_component_descs_adjust_ti:
  assumes wf_t: "wf_component_descs t"
  shows "wf_component_descs (adjust_ti t acc upd)"
using wf_component_descs_map_td_update_desc(1) [OF wf_t]
  by (simp add: adjust_ti_def)

lemma (in wf_xfield) update_desc_component_desc:
  shows
   "update_desc acc upd (component_desc (typ_info_t TYPE('a))) =
     field_access = xto_bytes  acc, field_update = upd  xfrom_bytes,
      field_sz = size_of TYPE('a)"
proof -
  have wf: "wf_component_descs (typ_info_t TYPE('a))" by (rule wf_component_descs)
  have eq: "bs v. field_update (component_desc (typ_info_t TYPE('a))) bs (acc v) =
                   field_update (component_desc (typ_info_t TYPE('a))) bs undefined"
    by (simp add: entire_update)
   show ?thesis
  using size_td_field_sz(1) [OF wf]
  apply (simp add: xto_bytes_def size_of_def update_desc_def)
  apply (rule ext)
  apply (rule ext)
  apply (simp add: xfrom_bytes_def eq)
  done
qed


lemma (in wf_xfield) wf_component_descs_ti_typ_combine:
  assumes wf_t: "wf_component_descs t"
  shows "wf_component_descs (ti_typ_combine ft acc upd algn fn t)"
proof -
  have wf_ft: "wf_component_descs (typ_info_t TYPE('a))" by (rule wf_component_descs)
  show ?thesis
  apply (simp add: ti_typ_combine_def Let_def)
  apply (rule wf_component_descs_extend_ti)
    apply (rule wf_t)
   apply (rule wf_component_descs_adjust_ti)
   apply (rule wf_ft)
  apply (simp add: adjust_ti_def Let_def update_desc_component_desc
      update_desc_component_desc_commutes[symmetric])
  done
qed

lemma (in wf_xfield) wf_component_descs_ti_typ_pad_combine:
  assumes wf_t: "wf_component_descs t"
  shows "wf_component_descs (ti_typ_pad_combine ft acc upd algn fn t)"
  apply (cases "0 < padup (max (2 ^ algn) (align_of TYPE('a))) (size_td t)")
   apply (simp add: ti_typ_pad_combine_def Let_def)
   apply (rule wf_component_descs_ti_typ_combine)
   apply (rule wf_component_descs_ti_pad_combine [OF wf_t])
  apply (simp add: ti_typ_pad_combine_def Let_def)
  apply (rule wf_component_descs_ti_typ_combine [OF wf_t])
  done


lemma component_descs_independent_empty_typ_info [simp]:
  "component_descs_independent  (empty_typ_info algn n)"
  by (simp add: empty_typ_info_def)


lemma component_descs_independent_list_appendI:
  assumes ind_xs_ys: "x  set (toplevel_field_descs_list xs).
       field_desc_independent (field_access x) (field_update x) (set (toplevel_field_descs_list ys))"
  assumes ind_xs: "component_descs_independent_list xs"
  assumes ind_ys: "component_descs_independent_list ys"
  shows "component_descs_independent_list (xs @ ys)"
  using ind_xs_ys ind_xs ind_ys
proof (induct xs arbitrary: ys)
  case Nil
  then show ?case by simp
next
  case (Cons x xs)
  obtain ft' fn' d' where x: "x = DTuple ft' fn' d'" by (cases x) simp

  from Cons.prems obtain

    find_d'_ys: "field_desc_independent (field_access d') (field_update d')
                   (set (toplevel_field_descs_list ys))" and
    find_xs_ys: "xset (toplevel_field_descs_list xs).
                   field_desc_independent (field_access x) (field_update x) (set (toplevel_field_descs_list ys))" and
    find_d'_xs: "field_desc_independent (field_access d') (field_update d') (set (toplevel_field_descs_list xs))" and
    find_xs: "field_descs_independent (toplevel_field_descs_list xs)" and
    ind_ft': "component_descs_independent ft'" and
    ind_ys: "component_descs_independent_list ys" and
    ind_xs:"component_descs_independent_list xs"
    by (clarsimp simp add: x)


  from find_d'_xs find_d'_ys
  have find_d': "field_desc_independent (field_access d') (field_update d')
                 (set (toplevel_field_descs_list xs)  set (toplevel_field_descs_list ys))"
    by (simp add: field_desc_independent_union_iff)

  from component_descs_list_field_descs_independent [OF ind_xs]
  have tl_xs: "field_descs_independent (toplevel_field_descs_list xs)".
  from component_descs_list_field_descs_independent [OF ind_ys]
  have tl_ys: "field_descs_independent (toplevel_field_descs_list ys)".

  from field_descs_independent_appendI1 [OF tl_xs tl_ys find_xs_ys]
  have tl_xs_ys: "field_descs_independent
                    (toplevel_field_descs_list xs @ toplevel_field_descs_list ys)" .

  from Cons.hyps [OF find_xs_ys ind_xs ind_ys]
  have ind_xs_ys: "component_descs_independent_list (xs @ ys)" .
  from find_d' tl_xs_ys ind_ft' ind_xs_ys
  show ?case
    by (simp add: x)
qed

lemma component_descs_independent_extend_ti:
  assumes ind_t: "component_descs_independent t"
  assumes ind_ft: "component_descs_independent ft"
  assumes ind_d_t: "field_desc_independent (field_access d) (field_update d) (set (toplevel_field_descs t))"
  shows "component_descs_independent (extend_ti t ft algn fn d)"
proof (cases t)
  case (TypDesc algn st nn)
  then show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from ind_ft show ?thesis
      by (simp add: TypDesc TypScalar)
  next
    case (TypAggregate fs)
    then show ?thesis
    proof (cases fs)
      case Nil
      from ind_ft show ?thesis
        by (simp add: TypDesc TypAggregate Nil)
    next
      case (Cons f fs')
      obtain ft' fn' d' where f: "f = DTuple ft' fn' d'" by (cases f) simp
      from ind_t obtain
        field_ind_d'_fs': "field_desc_independent (field_access d') (field_update d')
                            (set (toplevel_field_descs_list fs'))" and
        field_ind_fs': "field_descs_independent (toplevel_field_descs_list fs')" and
        comp_ind_ft': "component_descs_independent ft'" and
        comp_ind_fs': "component_descs_independent_list fs'"
        by (simp add: TypDesc TypAggregate Cons f)

      from ind_d_t obtain ind_d_d': "field_desc_independent (field_access d) (field_update d) {d'}" and
       ind_d_fs': "field_desc_independent (field_access d) (field_update d) (set (toplevel_field_descs_list fs'))"
        apply  (simp add: TypDesc TypAggregate Cons f)
        supply field_desc_independent_insert_iff[iff]
        by fastforce


      from field_desc_independent_symmetric [of "{d}" "{d'}"] ind_d_d'
      have field_ind_d'_d: "field_desc_independent (field_access d') (field_update d') {d}"
        by auto

      from field_ind_d'_fs' field_ind_d'_d
      have field_ind_d'_d_fs': "field_desc_independent (field_access d') (field_update d')
                                 (insert d (set (toplevel_field_descs_list fs')))"
        apply (subst  insert_is_Un )
        apply (simp only: field_desc_independent_union_iff)
        done

      have ind_d: "field_descs_independent [d]" by simp
      from field_desc_independent_symmetric [of "set [d]" "set (toplevel_field_descs_list fs')"] ind_d_fs'
      have ind_fs'_d:  "xset (toplevel_field_descs_list fs').
              field_desc_independent (field_access x) (field_update x) (set [d])" by simp
      from field_descs_independent_appendI1 [OF field_ind_fs' ind_d ind_fs'_d]
      have field_ind_fs'_d:"field_descs_independent (toplevel_field_descs_list fs' @ [d])" .

      from ind_fs'_d ind_ft
      have comp_ind_fs'_d: "component_descs_independent_list (fs' @ [DTuple ft fn d])"
        apply -
        apply (rule component_descs_independent_list_appendI [OF _ comp_ind_fs' ] )
         apply simp
        apply simp
        done
      from field_ind_d'_d_fs' field_ind_fs'_d comp_ind_ft' comp_ind_fs'_d
      show ?thesis
          by (simp add: TypDesc TypAggregate Cons f)
      qed
  qed
qed



(*
  "component_descs_independent_struct st
   ⟹ component_descs_independent_struct  (extend_ti_struct st ft fn d)"
  "component_descs_independent_list fs
   ⟹ component_descs_independent_list  (extend_ti_list fs ft fn d)"
*)
lemma fu_commutes_id1 [simp]: "fu_commutes (λbs. id) upd"
  by (auto simp add: fu_commutes_def)

lemma fu_commutes_id2 [simp]: "fu_commutes upd (λbs. id)"
  by (auto simp add: fu_commutes_def)

lemma field_desc_independent_pad: "field_desc_independent (λv bs. if n  length bs then take n bs else replicate n 0) (λbs. id) D"
  by (rule field_desc_independent.intro) auto

lemma component_descs_independent_ti_pad_combine:
  assumes ind_t: "component_descs_independent t"
  shows "component_descs_independent (ti_pad_combine n t)"
  apply (simp add: ti_pad_combine_def Let_def padding_desc_def)
  apply (rule component_descs_independent_extend_ti [OF ind_t])
   apply simp
  apply (simp add: field_desc_independent_pad)
  done


lemma (in wf_field) field_desc_independent_update_desc:
  assumes ind: "field_desc_independent (field_access d) (field_update d) D"
  shows "field_desc_independent (field_access (update_desc acc upd d)) (field_update (update_desc acc upd d))
          (update_desc acc upd ` D)" (is "field_desc_independent ?acc ?upd ?U")
proof -
  from ind
  interpret ind: field_desc_independent "field_access d" "field_update d" "D" .
  show ?thesis
  proof
    fix ud
    assume "ud  ?U"
    show "fu_commutes ?upd (field_update ud)"
      by (smt ud  update_desc acc upd ` D acc_upd double_update_upd field_desc.select_convs(2)
          field_desc_independent.fu_commutes fu_commutes_def imageE ind.field_desc_independent_axioms update_desc_def)
  next
    fix ud bs v bs'
    assume "ud  ?U"
    show "?acc (field_update ud bs v) bs' = ?acc v bs'"
      by (smt ud  update_desc acc upd ` D acc_upd field_desc.select_convs(1) field_desc.select_convs(2)
          field_desc_independent.acc_upd_old imageE ind.field_desc_independent_axioms o_apply update_desc_def)
  next
    fix ud bs' v bs
    assume "ud  ?U"
    show "field_access ud (?upd bs' v) bs = field_access ud v bs"
      by (smt ud  update_desc acc upd ` D acc_upd field_desc.select_convs(1) field_desc.select_convs(2)
          field_desc_independent.acc_upd_new imageE ind.field_desc_independent_axioms o_apply update_desc_def)
  qed
qed



lemma (in wf_field) field_descs_independent_update_desc:
  "field_descs_independent (toplevel_field_descs t)
   field_descs_independent (toplevel_field_descs
        (map_td (λn algn. update_desc acc upd) (update_desc acc upd) t))"
  "field_descs_independent (toplevel_field_descs_struct st)
   field_descs_independent (toplevel_field_descs_struct
        (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st))"
  "field_descs_independent (toplevel_field_descs_list fs)
   field_descs_independent (toplevel_field_descs_list
        (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs))"
  "field_descs_independent (toplevel_field_descs_tuple f)
   field_descs_independent (toplevel_field_descs_tuple
        (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) f))"
proof (induct t and st and fs and f)
  case (TypDesc st n)
  then show ?case by simp
next
  case (TypScalar sz align d)
  then show ?case by simp
next
  case (TypAggregate fs)
  then show ?case by simp
next
  case Nil_typ_desc
  then show ?case by simp
next
  case (Cons_typ_desc f fs)

  obtain ft' fn' d' where f: "f = DTuple ft' fn' d'" by (cases f) simp

  from Cons_typ_desc.prems
  have ind_f_fs: "field_descs_independent
     (toplevel_field_descs_tuple f @ toplevel_field_descs_list fs)" by simp

  from field_descs_independent_append_first [OF ind_f_fs]
  have ind_f: "field_descs_independent (toplevel_field_descs_tuple f)" .

  from field_descs_independent_append_second [OF ind_f_fs]
  have ind_fs: "field_descs_independent (toplevel_field_descs_list fs)" .


  from Cons_typ_desc.hyps(1) [OF ind_f]
  have ind_upd_f: "field_descs_independent
                    (toplevel_field_descs_tuple
                      (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) f))".

  from Cons_typ_desc.hyps(2) [OF ind_fs]
  have ind_upd_fs: "field_descs_independent
                     (toplevel_field_descs_list
                       (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs))" .


  from field_descs_independent_append_first_ind [OF ind_f_fs]
  have "field_desc_independent (field_access d') (field_update d') (set (toplevel_field_descs_list fs))"
    by (auto simp add: f)
  from field_desc_independent_update_desc [OF this]
  have "field_desc_independent (field_access (update_desc acc upd d')) (field_update (update_desc acc upd d'))
           (update_desc acc upd ` set (toplevel_field_descs_list fs))" .
  then
  have upd_d'_fs: "field_desc_independent (field_access (update_desc acc upd d')) (field_update (update_desc acc upd d'))
         (set (toplevel_field_descs_list
                 (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs)))"
    by (simp add: toplevel_field_descs_map)
  from ind_upd_fs upd_d'_fs
  have ind_upd_f_fs: "field_descs_independent
     (toplevel_field_descs_tuple
       (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) f) @
      toplevel_field_descs_list
       (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs))"
    by (simp add: f)
  from Cons_typ_desc ind_upd_f_fs
  show ?case by simp
next
  case (DTuple_typ_desc ft fn d)
  then show ?case by simp
qed




lemma (in wf_field) component_descs_independent_update_desc:
  "component_descs_independent t
   component_descs_independent
       (map_td (λn algn. update_desc acc upd) (update_desc acc upd) t)"
  "component_descs_independent_struct st
   component_descs_independent_struct
       (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st)"
  "component_descs_independent_list fs
   component_descs_independent_list
       (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs)"
  "component_descs_independent_tuple f
   component_descs_independent_tuple
       (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) f)"
proof (induct t and st and fs and f)
  case (TypDesc st n)
then show ?case by simp
next
  case (TypScalar sz align d)
  then show ?case by simp
next
case (TypAggregate fs)
then show ?case by simp
next
  case Nil_typ_desc
  then show ?case by simp
next
  case (Cons_typ_desc f fs)

  obtain ft' fn' d' where f: "f = DTuple ft' fn' d'" by (cases f) simp

  from Cons_typ_desc.prems obtain
    find_f_fs: "field_descs_independent
                (toplevel_field_descs_tuple f @ toplevel_field_descs_list fs)" and
    ind_f: "component_descs_independent_tuple f" and
    ind_fs: "component_descs_independent_list fs"
    by simp


  from field_descs_independent_append_first [OF find_f_fs]
  have fi_f: "field_descs_independent (toplevel_field_descs_tuple f)" .

  from Cons_typ_desc.hyps(1) [OF ind_f]
  have ind_upd_f: "component_descs_independent_tuple
          (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) f)" .
  from field_descs_independent_update_desc(4) [OF fi_f]
  have "field_descs_independent (toplevel_field_descs_tuple
         (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) f))" .
  with ind_upd_f
  have ind_upd_f': "component_descs_independent_list
          (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) [f])"  by simp


  from Cons_typ_desc.hyps(2) [OF ind_fs]
  have ind_upd_fs: "component_descs_independent_list
          (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs)" .
  from component_descs_list_field_descs_independent [OF this]
  have find_upd_fs: "field_descs_independent (toplevel_field_descs_list
          (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs))" .
  from field_descs_independent_append_first_ind [OF find_f_fs]
  have find_fs: "field_desc_independent (field_access d') (field_update d') (set (toplevel_field_descs_list fs))"
    by (auto simp add: f)
  from field_desc_independent_update_desc [OF this]
  have "field_desc_independent (field_access (update_desc acc upd d')) (field_update (update_desc acc upd d'))
           (update_desc acc upd ` set (toplevel_field_descs_list fs))" .
  then
  have upd_d'_fs: "field_desc_independent (field_access (update_desc acc upd d')) (field_update (update_desc acc upd d'))
         (set (toplevel_field_descs_list
                 (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs)))"
    by (simp add: toplevel_field_descs_map)

  from upd_d'_fs find_upd_fs
  have ind_f_fs: "field_descs_independent
      (toplevel_field_descs_tuple
         (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) f) @
       toplevel_field_descs_list
         (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) fs))"
    by (simp add: f)
  from Cons_typ_desc ind_f_fs  show ?case
    by (simp)
next
  case (DTuple_typ_desc ft fn d)
  then show ?case by simp
qed


lemma (in wf_field) component_descs_independent_adjust_ti:
  assumes ind_t: "component_descs_independent t"
  shows "component_descs_independent (adjust_ti t acc upd)"
  apply (simp add: adjust_ti_def)
  apply (rule component_descs_independent_update_desc(1) [OF ind_t])
  done



theorem (in wf_xfield) component_descs_independent_ti_typ_combine:
  fixes
    ft::"'a::xmem_type itself" and
     t:: "'s xtyp_info"
   assumes ind_t: "component_descs_independent t"
   assumes ind_acc_upd: "field_desc_independent (xto_bytes  acc) (upd  xfrom_bytes)
                          (set (toplevel_field_descs t))"
  shows "component_descs_independent (ti_typ_combine ft acc upd algn fn t)"
  apply (simp add: ti_typ_combine_def)
  apply (rule component_descs_independent_extend_ti [OF ind_t])
   apply (rule component_descs_independent_adjust_ti [OF component_descs_independent])
  apply simp
  apply (rule ind_acc_upd)
  done


lemma (in wf_xfield) wf_field_desc_extend_ti:
   assumes ind_t: "field_desc_independent (xto_bytes  acc) (upd  xfrom_bytes) (set (toplevel_field_descs t))"
   assumes ind_d: "field_desc_independent (xto_bytes  acc) (upd  xfrom_bytes) {d}"
   shows
   "field_desc_independent (xto_bytes  acc) (upd  xfrom_bytes)
         (set (toplevel_field_descs (extend_ti t ft algn fn d)))"
proof (cases t)
  case (TypDesc algn' st nn)
  then show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    from ind_d show ?thesis
      by (simp add: TypDesc TypScalar)
  next
    case (TypAggregate fs)
    then show ?thesis
    proof (cases fs)
      case Nil
      from ind_d show ?thesis
        by (simp add: TypDesc TypAggregate Nil)
    next
      case (Cons f fs')
      obtain ft' fn' d' where f: "f = DTuple ft' fn' d'" by (cases f) simp
      from ind_d ind_t
      show ?thesis
        apply (simp add: TypDesc TypAggregate Cons f)
        by (meson field_desc_independent_insert_iff)
    qed
  qed
qed

lemma (in wf_xfield) field_desc_independent_ti_pad_combine:
   assumes ind_acc_upd: "field_desc_independent (xto_bytes  acc) (upd  xfrom_bytes)
                          (set (toplevel_field_descs t))"
   shows "field_desc_independent (xto_bytes  acc) (upd  xfrom_bytes)
           (set (toplevel_field_descs (ti_pad_combine n t)))"
  apply (simp add: ti_pad_combine_def Let_def padding_desc_def)
  apply (rule wf_field_desc_extend_ti [OF ind_acc_upd])
  by (auto simp add: field_desc_independent_def)

theorem (in wf_xfield) component_desc_independent_ti_typ_pad_combine:
  fixes
    ft::"'a::xmem_type itself" and
     t:: "'s xtyp_info"
   assumes ind_t: "component_descs_independent t"
   assumes ind_acc_upd: "field_desc_independent (xto_bytes  acc) (upd  xfrom_bytes)
                          (set (toplevel_field_descs t))"
   shows "component_descs_independent (ti_typ_pad_combine ft acc upd algn fn t)"

  apply (cases "0 < padup (max (2 ^ algn) (align_of TYPE('a))) (size_td t)")
   apply (simp add: ti_typ_pad_combine_def Let_def)
   apply (rule component_descs_independent_ti_typ_combine)
    apply (rule component_descs_independent_ti_pad_combine [OF ind_t])
   apply (rule field_desc_independent_ti_pad_combine [OF ind_acc_upd])
  apply (simp add: ti_typ_pad_combine_def Let_def)
  apply (rule component_descs_independent_ti_typ_combine [OF ind_t ind_acc_upd])
  done

lemma component_descs_independent_map_align[simp]:
"component_descs_independent (map_align f t) = component_descs_independent t"
  by (cases t) simp

lemma component_descs_independent_final_pad:
   assumes ind_t: "component_descs_independent t"
   shows "component_descs_independent (final_pad algn t)"
  apply (clarsimp simp add: final_pad_def Let_def ind_t)
  apply (rule  component_descs_independent_ti_pad_combine [OF ind_t])
  done


theorem (in xmem_contained_type) contained_field_descs_ti_typ_combine:
  fixes
    ft::"'a itself" and
     t:: "'b xtyp_info"
  assumes contained_t: "contained_field_descs t"
  shows "contained_field_descs (ti_typ_combine ft acc upd algn fn t)"
proof -
  from contained_field_descs_adjust_ti [OF contained_field_descs]
  have "contained_field_descs (adjust_ti (typ_info_t TYPE('a)) acc upd)" .
  moreover
  define d::"'b field_desc"
    where "d  field_access = xto_bytes  acc, field_update = upd  xfrom_bytes,
                field_sz = size_of TYPE('a)"

  from fields_contained_update_desc_mem_type [of acc upd]
  have "fields_contained (field_access d) (field_update d)
           (set (toplevel_field_descs (adjust_ti (typ_info_t TYPE('a)) acc upd)))"
    by (simp add: toplevel_field_descs_adjust_ti d_def)
  ultimately
  show ?thesis
    using contained_t
    by (simp add: ti_typ_combine_def contained_field_descs_extend_ti d_def)
qed


theorem (in xmem_contained_type) contained_field_descs_ti_typ_pad_combine:
  fixes
    ft::"'a itself" and
     t:: "'b xtyp_info"
  assumes contained_t: "contained_field_descs t"
  shows "contained_field_descs (ti_typ_pad_combine ft acc upd algn fn t)"
  using contained_t contained_field_descs
  by (simp add: ti_typ_pad_combine_def Let_def contained_field_descs_ti_typ_combine contained_field_descs_ti_pad_combine)


locale ti_ind' =
  fixes X :: "'a leaf_desc set"
  fixes Y :: "'a leaf_desc set"
  assumes fu_commutes: "x  X   y  Y  fu_commutes (field_update (lf_fd x)) (field_update (lf_fd y))"
  assumes fa_fu_ind_X: "x  X   y  Y  fa_fu_ind (lf_fd x) (lf_fd y) (lf_sz y) (lf_sz x)"
  assumes fa_fu_ind_Y: "x  X   y  Y  fa_fu_ind (lf_fd y) (lf_fd x) (lf_sz x) (lf_sz y)"

lemma ti_ind'_ti_ind: "ti_ind' X Y = ti_ind X Y"
  by (auto simp add: ti_ind_def ti_ind'_def)

lemma fields_contained_transitive:
  assumes d_in: "d  D"
  assumes d_contains : "fields_contained (field_access d) (field_update d) X"
  assumes contained: "fields_contained acc upd D"
  shows "fields_contained acc upd X"
  using d_in d_contains contained unfolding fields_contained_def
  by metis


lemma fields_contained_singleton [simp]:
  "fields_contained (field_access d) (field_update d) {d}"
  by (auto simp add: fields_contained_def)

(* make inductive over other cases *)
lemma contained_field_descs_leaf:
  "contained_field_descs t  ld  lf_fd ` (lf_set t []) 
     d  set (toplevel_field_descs t). fields_contained (field_access d) (field_update d) {ld}"
  "contained_field_descs_struct st  ld  lf_fd ` (lf_set_struct st []) 
     d  set (toplevel_field_descs_struct st). fields_contained (field_access d) (field_update d) {ld}"
  "contained_field_descs_list fs  ld  lf_fd ` (lf_set_list fs []) 
     d  set (toplevel_field_descs_list fs). fields_contained (field_access d) (field_update d) {ld}"
  "contained_field_descs_tuple f  ld  lf_fd ` (lf_set_tuple f []) 
     d  set (toplevel_field_descs_tuple f). fields_contained (field_access d) (field_update d) {ld}"
proof (induct t and st and fs and f)
  case (TypDesc st n)
  then show ?case by auto
next
  case (TypScalar n sz d)
  then show ?case by auto
next
  case (TypAggregate fs)
  then show ?case by auto
next
  case Nil_typ_desc
  then show ?case by auto
next
  case (Cons_typ_desc f fs)
  then show ?case by auto
next
  case (DTuple_typ_desc ft fn d)
  then show ?case
    by (metis contained_field_descs_tuple.simps toplevel_field_descs_tuple.simps fields_contained_transitive
     insertI1 lf_fd_fn(1) lf_set_tuple.simps list.simps(15))
qed




lemma wf_field_desc_wf_lf:
"wf_field_desc d  sz = field_sz d   wf_lf {lf_fd = d, lf_sz = sz, lf_fn = xs}"
  by (simp add: wf_field_desc_def
fd_cons_access_update_def fd_cons_desc_def fd_cons_double_update_def fd_cons_length_def
fd_cons_update_access_def padding_lense.access_result_size padding_lense.access_update
padding_lense.double_update padding_lense.update_access wf_lf_def)


lemma wf_lf_unionI: "wf_lf A  wf_lf B  ti_ind' A B  wf_lf (A  B)"
  by (auto simp add: wf_lf_def ti_ind'_def fu_commutes_def)


lemma fields_contained_subset:
  assumes cont_X: "fields_contained acc upd X"
  assumes subs: "Y  X"
  shows "fields_contained acc upd Y"
proof -
  from cont_X interpret X: fields_contained acc upd X .
  show ?thesis
  proof
    fix d s s'
    assume d: "d  Y"
    assume acc: "acc s = acc s'"
    show "field_access d s = field_access d s'"
      using d subs acc X.access_contained by blast
  next
    fix d bs s
    assume d: "d  Y"
    show "bs'.  s'. acc s' = acc s  field_update d bs s' = upd bs' s'"
      using d subs X.update_contained by blast
  qed
qed


lemma fields_contained_unionD1:
  assumes "fields_contained acc upd (X  Y)"
  shows "fields_contained acc upd X"
  using assms
  by (auto intro: fields_contained_subset)


lemma fields_contained_unionD2:
  assumes "fields_contained acc upd (X  Y)"
  shows "fields_contained acc upd Y"
  using assms
  by (auto intro: fields_contained_subset)

lemma fields_contained_unionI:
  assumes cont_X: "fields_contained acc upd X"
  assumes cont_Y: "fields_contained acc upd Y"
  shows "fields_contained acc upd (X  Y)"
proof -
  from cont_X interpret X: fields_contained acc upd X .
  from cont_Y interpret Y: fields_contained acc upd Y .
  show ?thesis
  proof
    fix d s s'
    assume d: "d  X  Y"
    assume acc: "acc s = acc s'"
    show "field_access d s = field_access d s'"
      using d acc X.access_contained Y.access_contained by blast
  next
    fix d bs s
    assume d: "d  X  Y"
    show "bs'.  s'. acc s' = acc s  field_update d bs s' = upd bs' s'"
      using d X.update_contained Y.update_contained by blast
  qed
qed

(* fixme: move up *)
lemma fields_contained_insertI:
  assumes cont_x: "fields_contained acc upd {x}"
  assumes cont_Y: "fields_contained acc upd Y"
  shows "fields_contained acc upd (insert x Y)"
  using fields_contained_unionI [OF cont_x cont_Y]
  by simp



lemma fields_contained_toplevel_to_field_descs:
  "(acc::'a  byte list  byte list) upd.
   contained_field_descs t  fields_contained acc upd (set (toplevel_field_descs t))
    fields_contained acc upd (set (field_descs t))"
  "(acc::'a  byte list  byte list) upd.
  contained_field_descs_struct st  fields_contained acc upd (set (toplevel_field_descs_struct st))
    fields_contained acc upd (set (field_descs_struct st))"
  "(acc::'a  byte list  byte list) upd.
  contained_field_descs_list fs  fields_contained acc upd (set (toplevel_field_descs_list fs))
    fields_contained acc upd (set (field_descs_list fs))"
  "(acc::'a  byte list  byte list) upd.
   contained_field_descs_tuple f  fields_contained acc upd (set (toplevel_field_descs_tuple f))
    fields_contained acc upd (set (field_descs_tuple f))"
proof (induct t and st and fs and f)
case (TypDesc st n)
  then show ?case by simp
next
  case (TypScalar st align d)
  then show ?case by simp
next
  case (TypAggregate fs)
  then show ?case by simp
next
  case Nil_typ_desc
  then show ?case by simp
next
  case (Cons_typ_desc f fs)
  from Cons_typ_desc.prems obtain
     fcont_f_fs: "fields_contained acc upd
                  (set (toplevel_field_descs_tuple f)  set (toplevel_field_descs_list fs))" and
     cont_f: "contained_field_descs_tuple f" and
     cont_fs: "contained_field_descs_list fs" by clarsimp

  note fcont_f = fields_contained_unionD1 [OF fcont_f_fs]
  note fcont_fs = fields_contained_unionD2 [OF fcont_f_fs]

  from Cons_typ_desc.hyps(1) [OF cont_f fcont_f] Cons_typ_desc.hyps(2) [OF cont_fs fcont_fs]
  have "fields_contained acc upd (set (field_descs_tuple f)  set (field_descs_list fs))"
    by (rule fields_contained_unionI)

  then show ?case
    by clarsimp

next
  case (DTuple_typ_desc ft fn d)
  then show ?case
    by (fastforce intro: fields_contained_insertI fields_contained_transitive)
qed


lemma fu_commutes_intro:
  assumes "v bs bs'. f bs (g bs' v) = g bs' (f bs v)"
  shows "fu_commutes f g"
  using assms by (simp add: fu_commutes_def)


lemma (in wf_field_desc) access_same_update_id:
  assumes "field_access d (field_update d bs v) bs' = field_access d v bs'"
  shows "field_update d bs v = v"
  by (metis assms double_update update_access)


lemma (in wf_field_desc) access_same_update_id':
  assumes upd_inv: "field_update d bs v = v"
  assumes acc_same: "field_access d v bs = field_access d v' bs"
  shows "field_update d bs v' = v'"
  by (metis acc_same access_update double_update upd_inv update_access)

lemma (in wf_field_desc) update_access_unequal:
  assumes neq_upd: "field_update d bs v  v"
  shows "field_access d v bs'  field_access d (field_update d bs v) bs'"
  by (metis access_same_update_id neq_upd)

lemma (in wf_field_desc) access_eq_update_eq:
  assumes "bs'. field_access d (field_update d bs v) bs' = field_access d v bs'"
  shows "field_update d bs v = v"
  by (metis assms double_update update_access)





lemma field_desc_independent_contained_transitive:
  assumes cont: "fields_contained (field_access e) (field_update e) D"
  assumes ind:  "field_desc_independent (field_access d) (field_update d) {e}"
  shows "field_desc_independent (field_access d) (field_update d) D"
proof -
  from cont interpret cont_e: fields_contained "field_access e" "field_update e" D .
  from ind interpret ind_e: field_desc_independent "field_access d" "field_update d" "{e}" .
  show ?thesis
  proof
    fix f
    assume f_in: "f  D"
    show "fu_commutes (field_update d) (field_update f)"
    proof (rule fu_commutes_intro)
      fix v bs bs'

      from ind_e.acc_upd_new [of e]
      have e_d_ind: "field_access e (field_update d bs v) = field_access e v"
        by (rule ext) auto

      from cont_e.update_contained [OF f_in, where s=v] e_d_ind
      obtain bs1 where f_e_v: "field_update f bs' v = field_update e bs1 v" and
                       f_e_upd_v: "field_update f bs' (field_update d bs v) = field_update e bs1 (field_update d bs v)"

        by blast
      have "field_update d bs (field_update f bs' v) = field_update d bs (field_update e bs1 v)"
        by (simp add: f_e_v)
      also
      from ind_e.fu_commutes [of e] have " = field_update e bs1 (field_update d bs v)"
        by (auto simp add: fu_commutes_def)
      also have " = field_update f bs' (field_update d bs v)" by (simp add: f_e_upd_v)
      finally
      show "field_update d bs (field_update f bs' v) =
            field_update f bs' (field_update d bs v)".
    qed
  next
    fix f bs v bs'
    assume f_in: "f  D"
    show "field_access d (field_update f bs v) bs' = field_access d v bs'"
      by (metis cont_e.update_contained f_in ind_e.acc_upd_old insertI1)
  next
    fix f bs' v bs
    assume f_in: "f  D"
    show "field_access f (field_update d bs' v) bs = field_access f v bs"
    proof -
     from ind_e.acc_upd_new [of e]
     have e_d_ind: "field_access e (field_update d bs' v) = field_access e v"
        by (rule ext) auto
     from cont_e.access_contained [OF f_in e_d_ind]
     show ?thesis by simp
   qed
 qed
qed


lemma field_desc_independent_contained_toplevel_to_field_descs:
  assumes cont_fs: "contained_field_descs_list fs"
  assumes ind_tl: "field_desc_independent (field_access d) (field_update d)
            (set (toplevel_field_descs_list fs))"
  shows "field_desc_independent (field_access d) (field_update d)
           (set (field_descs_list fs))"
  using cont_fs ind_tl
proof (induct fs)
  case Nil
  then show ?case by simp
next
  case (Cons f fs)
  obtain ft fn d' where f: "f = DTuple ft fn d'" by (cases f) simp

  from Cons.prems obtain
    ind_d_tl: "field_desc_independent (field_access d) (field_update d)
                (insert d' (set (toplevel_field_descs_list fs)))" and
    cont_ft: "contained_field_descs ft" and
    cont_d'_ft: "fields_contained (field_access d') (field_update d')
                   (set (toplevel_field_descs ft))" and
    cont_fs: "contained_field_descs_list fs"
    by (simp add: f)


  note ind_d_fs_tl = field_desc_independent_insertD2 [OF ind_d_tl]

  from Cons.hyps [OF cont_fs ind_d_fs_tl]
  have ind_d_fs: "field_desc_independent (field_access d) (field_update d)
                   (set (field_descs_list fs))".

  from fields_contained_toplevel_to_field_descs(1) [OF cont_ft cont_d'_ft]
  have fcont_d'_ft: "fields_contained (field_access d') (field_update d')
                      (set (field_descs ft))" .

  from field_desc_independent_insertD1 [OF ind_d_tl]
  have ind_d_d': "field_desc_independent (field_access d) (field_update d) {d'}" .

  from field_desc_independent_contained_transitive [OF fcont_d'_ft ind_d_d']
  have "field_desc_independent (field_access d) (field_update d) (set (field_descs ft))" .


  from field_desc_independent_unionI [OF this ind_d_fs] field_desc_independent_insertD1 [OF ind_d_tl]
  have "field_desc_independent (field_access d) (field_update d)
         (insert d' (set (field_descs ft)  set (field_descs_list fs)))"
    by (blast intro: field_desc_independent_insertI)
  then show ?case
    by (clarsimp simp add: f)
qed

theorem component_descs_independent_contained_wf_lf:
  fixes t::"'a xtyp_info" and
   st::"'a xtyp_info_struct" and
   fs::"'a xtyp_info_tuple list" and
   f::"'a xtyp_info_tuple"
 shows
 "ps. wf_desc t; wf_component_descs t; wf_field_descs (set (field_descs t)); component_descs_independent t;
  contained_field_descs t 
   wf_lf (lf_set t ps)"
 "ps. wf_desc_struct st; wf_component_descs_struct st; wf_field_descs (set (field_descs_struct st));
   component_descs_independent_struct st; contained_field_descs_struct st
   wf_lf (lf_set_struct st ps)"
 "ps. wf_desc_list fs; wf_component_descs_list fs; wf_field_descs (set (field_descs_list fs));
   component_descs_independent_list fs; contained_field_descs_list fs
   wf_lf (lf_set_list fs ps)"
 "ps. wf_desc_tuple f; wf_component_descs_tuple f; wf_field_descs (set (field_descs_tuple f));
   component_descs_independent_tuple f; contained_field_descs_tuple f
   wf_lf (lf_set_tuple f ps)"
proof (induct t and st and fs and f)
case (TypDesc algn st n)
  then show ?case by simp
next
  case (TypScalar sz align d)
  then show ?case by (simp add: wf_field_desc_wf_lf)
next
  case (TypAggregate fs)
then show ?case by simp
next
  case Nil_typ_desc
  then show ?case by simp
next
  case (Cons_typ_desc f fs)
  obtain ft' fn' d' where f: "f = DTuple ft' fn' d'" by (cases f) simp
  from Cons_typ_desc.prems obtain
    wf_f: "wf_desc_tuple f" and
    wf_fs: "wf_desc_list fs" and
    wf_cd_f: "wf_component_descs_tuple f" and
    wf_cd_fs: "wf_component_descs_list fs" and
    wf_fd_f: "wf_field_descs (set (field_descs_tuple f))" and
    wf_fd_fs: "wf_field_descs (set (field_descs_list fs))" and
    ind_f_fs: "field_descs_independent
                (toplevel_field_descs_tuple f @ toplevel_field_descs_list fs)" and
    cont_f: "contained_field_descs_tuple f" and
    cont_fs: "contained_field_descs_list fs" and
    dist_names: "dt_snd f  dt_snd ` set fs" and
    ind_f: "component_descs_independent_tuple f" and
    ind_fs:"component_descs_independent_list fs"
    by clarsimp

  from Cons_typ_desc.hyps(1) [OF wf_f wf_cd_f wf_fd_f ind_f cont_f]
  have wf_lf_ft': "wf_lf (lf_set ft' (ps @ [fn']))" by (simp add: f)

  from Cons_typ_desc.hyps(2) [OF wf_fs wf_cd_fs wf_fd_fs ind_fs cont_fs]
  have wf_lf_fs: "wf_lf (lf_set_list fs ps)" .


  from field_descs_independent_append_first_ind [OF ind_f_fs, of d']
  have "field_desc_independent (field_access d') (field_update d')
            (set (toplevel_field_descs_list fs))" by (simp add: f)


  from cont_f field_desc_independent_contained_toplevel_to_field_descs [OF cont_fs, where d=d'] this
  have ind_d'_fs: "field_desc_independent (field_access d') (field_update d')
                       (set (field_descs_list fs))"
    by (simp add: f)

  from cont_f fields_contained_toplevel_to_field_descs
  have cont_d'_ft': "fields_contained (field_access d') (field_update d') (set (field_descs ft'))"
    by (auto simp add: f)

  have ti_ind: "ti_ind' (lf_set ft' (ps @ [fn'])) (lf_set_list fs ps)"
  proof
    fix x y
    assume x_in: "x  lf_set ft' (ps @ [fn'])"
    assume y_in: "y  lf_set_list fs ps"
    from lf_set_subset_field_descs(1) x_in
    have x_in': "lf_fd x  set (field_descs ft')" by blast
    from lf_set_subset_field_descs(3) y_in
    have y_in': "lf_fd y  set (field_descs_list fs)" by blast

    from field_desc_independent_symmetric_singleton [OF ind_d'_fs y_in']
    have "field_desc_independent (field_access (lf_fd y)) (field_update (lf_fd y)) {d'}" .

    from field_desc_independent_contained_transitive [OF cont_d'_ft' this]
    have "field_desc_independent (field_access (lf_fd y)) (field_update (lf_fd y))
            (set (field_descs ft'))" .

    from field_desc_independent.fu_commutes [OF this x_in'] fu_commutes_sym
    show "fu_commutes (field_update (lf_fd x)) (field_update (lf_fd y))"
      by blast
  next
    fix x y
    assume x_in: "x  lf_set ft' (ps @ [fn'])"
    assume y_in: "y  lf_set_list fs ps"
    from lf_set_subset_field_descs(1) x_in
    have x_in': "lf_fd x  set (field_descs ft')" by blast
    from lf_set_subset_field_descs(3) y_in
    have y_in': "lf_fd y  set (field_descs_list fs)" by blast

    from field_desc_independent_symmetric_singleton [OF ind_d'_fs y_in']
    have "field_desc_independent (field_access (lf_fd y)) (field_update (lf_fd y)) {d'}" .

    from field_desc_independent_contained_transitive [OF cont_d'_ft' this]
    have "field_desc_independent (field_access (lf_fd y)) (field_update (lf_fd y))
            (set (field_descs ft'))" .
    from field_desc_independent.acc_upd_new [OF this x_in']
    show "fa_fu_ind (lf_fd x) (lf_fd y) (lf_sz y) (lf_sz x)"
      by (auto simp add: fa_fu_ind_def)
  next
    fix x y
    assume x_in: "x  lf_set ft' (ps @ [fn'])"
    assume y_in: "y  lf_set_list fs ps"
    from lf_set_subset_field_descs(1) x_in
    have x_in': "lf_fd x  set (field_descs ft')" by blast
    from lf_set_subset_field_descs(3) y_in
    have y_in': "lf_fd y  set (field_descs_list fs)" by blast

    from field_desc_independent_symmetric_singleton [OF ind_d'_fs y_in']
    have "field_desc_independent (field_access (lf_fd y)) (field_update (lf_fd y)) {d'}" .

    from field_desc_independent_contained_transitive [OF cont_d'_ft' this]
    have "field_desc_independent (field_access (lf_fd y)) (field_update (lf_fd y))
            (set (field_descs ft'))" .
    from field_desc_independent.acc_upd_old [OF this x_in']
    show "fa_fu_ind (lf_fd y) (lf_fd x) (lf_sz x) (lf_sz y)"
      by (auto simp add: fa_fu_ind_def)
  qed

  from wf_lf_unionI [OF wf_lf_ft' wf_lf_fs ti_ind]
  have "wf_lf (lf_set ft' (ps @ [fn'])  lf_set_list fs ps)" .

  then show ?case by (simp add: f)

next
  case (DTuple_typ_desc ft fn d)
  then show ?case by simp
qed

definition "wf_align_field ti  wf_align ti  align_field ti"



lemma wf_align_field_empty_typ_info: "wf_align_field (empty_typ_info algn n)"
  by (simp add: wf_align_field_def wf_align_simps align_field_empty_typ_info)

lemma (in mem_type) wf_align_field_ti_typ_pad_combine:
  "aggregate ti  wf_align_field ti 
      wf_align_field (ti_typ_pad_combine (TYPE('a)) acc upd algn fn ti)"
  by (auto simp add:  wf_align_field_def wf_align_ti_typ_pad_combine align_field_ti_typ_pad_combine)

lemma (in mem_type) wf_align_field_ti_typ_combine:
  "aggregate ti  wf_align_field ti  2 ^ align_td (typ_info_t TYPE('a)) dvd size_td ti 
      wf_align_field (ti_typ_combine (TYPE('a)) acc upd algn fn ti)"
  by (auto simp add: wf_align_field_def wf_align_ti_typ_combine align_field_ti_typ_combine)

lemma wf_align_field_ti_pad_combine: "aggregate ti  wf_align_field ti  wf_align_field (ti_pad_combine n ti)"
  by (auto simp add: wf_align_field_def wf_align_ti_pad_combine align_field_ti_pad_combine)

lemma wf_align_field_final_pad: "aggregate ti  wf_align_field ti  wf_align_field (final_pad algn ti)"
  by (auto simp add: wf_align_field_def wf_align_final_pad align_field_final_pad)

lemmas wf_align_field_simps =
  wf_align_field_empty_typ_info
  wf_align_field_ti_typ_pad_combine
  wf_align_field_ti_typ_combine
  wf_align_field_ti_pad_combine
  wf_align_field_final_pad


text ‹ The following theorem is used to prove that a new type is in class
@{class xmem_contained_type}, for which we have constructed the extended type info with:
  @{const empty_typ_info}
  @{const ti_typ_pad_combine} (@{const ti_typ_combine}, @{const ti_pad_combine})
  @{const final_pad}.

Note that the field-types are already in @{class xmem_contained_type}.

›
theorem tuned_xmem_contained_type_class_intro:
 assumes wf_desc: "wf_desc (typ_info_t TYPE('a))"
 assumes wf_size_desc: "wf_size_desc (typ_info_t TYPE('a))"
 assumes align_dvd: "align_of TYPE('a) dvd size_of TYPE('a)"
 assumes wf_align_field: "wf_align_field (typ_info_t TYPE('a))"
 assumes size: "size_of TYPE('a) < addr_card"
 assumes entire_update: "bs v w. length bs = size_of TYPE('a)
             field_update (component_desc (typ_info_t TYPE('a))) bs v =
                field_update (component_desc (typ_info_t TYPE('a))) bs w"
 assumes wf_component_descs: "wf_component_descs (typ_info_t TYPE('a))"
 assumes ind: "component_descs_independent (typ_info_t TYPE('a))"
 assumes wf_field_descs: "wf_field_descs (set (field_descs (typ_info_t TYPE('a))))"
 assumes contained_field_descs: "contained_field_descs (typ_info_t TYPE('a))"
 assumes wf_padding: "wf_padding (typ_info_t TYPE('a))"
 shows "OFCLASS('a::c_type, xmem_contained_type_class)"
proof
  show "wf_desc (typ_info_t TYPE('a))"
    by (rule wf_desc)
next
  show "wf_size_desc (typ_info_t TYPE('a))"
    by (rule wf_size_desc)
next
  show "wf_lf (lf_set (typ_info_t TYPE('a)) [])"
  proof -
    text ‹We can show that all leafs of the tree are disjoint, by exploiting the correct
          nesting of fields in the toplevel_structure›.›
    from component_descs_independent_contained_wf_lf(1) [OF wf_desc wf_component_descs
         wf_field_descs ind contained_field_descs]
    show ?thesis .
  qed
next
  fix bs v w
  show "length bs = size_of TYPE('a) 
       update_ti_t (typ_info_t TYPE('a)) bs v =
       update_ti_t (typ_info_t TYPE('a)) bs w"
  proof
    text ‹The updates are captured by the component-descriptor of the toplevel structure.›
    assume len: "length bs = size_of TYPE('a)"
    from entire_update [OF len] wf_field_descs len wf_component_descs
    show "update_ti_t (typ_info_t TYPE('a)) bs v =
       update_ti_t (typ_info_t TYPE('a)) bs w"
      by (simp add: ind size_of_def update_ti_component_desc_compatible(1) update_ti_t_def)
  qed
next
  show "align_of TYPE('a) dvd size_of TYPE('a)" by (rule align_dvd)
next
  from wf_align_field
  show "align_field (typ_info_t TYPE('a))" by (simp add: wf_align_field_def)
next
  show "size_of TYPE('a) < addr_card" by (rule size)
next
  show "wf_component_descs (typ_info_t TYPE('a))" by (rule wf_component_descs)
next
  show "component_descs_independent (typ_info_t TYPE('a))" by (rule ind)
next
  show "wf_field_descs (set (field_descs (typ_info_t TYPE('a))))" by (rule wf_field_descs)
next
  show "contained_field_descs (typ_info_t TYPE('a))" by (rule contained_field_descs)
next
  from wf_align_field
  show "wf_align (typ_info_t TYPE('a))"
    by (simp add: wf_align_field_def)
next
  from wf_padding
  show "wf_padding (typ_info_t TYPE('a))" .
qed

lemma field_sz_extend_ti: "aggregate t 
  field_sz (component_desc (extend_ti t ft algn fn d)) = field_sz (component_desc t) + field_sz d"
  apply (cases t)
  subgoal for x1 st n
    apply (cases st)
     apply (simp)
    subgoal for fs
      apply simp
      done
    done
  done

lemma field_sz_empty_typ_info: "field_sz (component_desc (empty_typ_info algn n)) = 0"
  by (simp add: empty_typ_info_def)

lemma (in c_type) field_sz_ti_typ_combine:
  fixes acc:: "'s  'a"
  assumes agg: "aggregate t"
  shows " field_sz (component_desc (ti_typ_combine ft acc upd algn fn t)) =
    field_sz (component_desc t) +  size_of TYPE('a)"
  using agg
  by (simp add: ti_typ_combine_def Let_def field_sz_extend_ti )

lemma (in c_type) field_sz_ti_pad_combine:
  fixes acc:: "'s  'a"
  assumes agg: "aggregate t"
  shows " field_sz (component_desc (ti_pad_combine n t)) =
    field_sz (component_desc t) +  n"
  using agg
  by (simp add: ti_pad_combine_def Let_def field_sz_extend_ti padding_desc_def)

lemma (in c_type) field_sz_ti_typ_pad_combine:
  fixes acc:: "'s  'a"
  assumes agg: "aggregate t"
  shows "field_sz (component_desc (ti_typ_pad_combine ft acc upd algn fn t)) =
    field_sz (component_desc t) +  size_of TYPE('a) + padup (max (2 ^ algn) (align_of TYPE('a))) (size_td t)"
  using agg
  by (simp add: ti_typ_pad_combine_def Let_def field_sz_ti_pad_combine field_sz_ti_typ_combine)

lemma component_desc_map_align[simp]:"component_desc (map_align f t) = component_desc t"
  by (cases t) simp

lemma field_sz_final_pad:
  assumes agg: "aggregate t"
  shows " field_sz (component_desc (final_pad algn t)) =
    field_sz (component_desc t) + padup (2^(max algn (align_td t))) (size_td t)"
  using agg
  by (simp add: final_pad_def Let_def field_sz_ti_pad_combine)




lemma split_fold_append: "split_fold f (xs@ys) bs s =
(let (s', bs') = split_fold f xs bs s in split_fold f ys bs' s')"
  apply (induct xs arbitrary: bs ys s)
  apply simp
   apply clarsimp
  by (metis prod.case_distrib)

lemma apply_field_updates_append: "apply_field_updates (xs@ys) bs s =
(let (s', bs') = apply_field_updates xs bs s in apply_field_updates ys bs' s')"
  by (simp add: apply_field_updates_def split_fold_append)

lemma snd_apply_field_updates: "snd (apply_field_updates ds bs s) = (drop (foldl (+) 0 (map field_sz ds)) bs)"
  apply (induct ds arbitrary:bs s)
   apply simp
  apply (simp add: add.commute sum_nat_foldl)
  done


lemma field_update_extend_ti:
  assumes agg: "aggregate t"
  shows "field_update (component_desc (extend_ti t ft algn fn d)) bs v =
         field_update d ((drop (field_sz (component_desc t))) bs)
           (field_update (component_desc t) bs v)"
proof (cases t)
  case (TypDesc algn st n)
  show ?thesis
  proof (cases st)
    case (TypScalar sz align d)
    with agg show ?thesis by (simp add: TypDesc)
  next
    case (TypAggregate fs)
    from snd_apply_field_updates
    have "fst (apply_field_updates (map dt_trd fs @ [d]) bs v) =
          field_update d (drop (foldl (+) 0 (map (field_sz  dt_trd) fs)) bs)
           (fst (apply_field_updates (map dt_trd fs) bs v))"
      by (simp add: apply_field_updates_append case_prod_beta snd_apply_field_updates)

    then show ?thesis by (simp add: TypDesc TypAggregate)
  qed
qed


lemma field_update_empty_typ_info: "field_update (component_desc (empty_typ_info algn n)) bs s = s"
  by (simp add: empty_typ_info_def)

lemma (in c_type) field_update_ti_typ_combine:
  assumes agg: "aggregate t"
  shows "field_update (component_desc (ti_typ_combine (ft::'a itself) acc upd algn fn t)) bs v =
         (upd o xfrom_bytes) ((drop (field_sz (component_desc t))) bs)
           (field_update (component_desc t) bs v)"
  using agg
  by (simp add: ti_typ_combine_def field_update_extend_ti)

lemma field_update_ti_pad_combine:
  assumes agg: "aggregate t"
  shows "field_update (component_desc (ti_pad_combine n t)) bs v =
           field_update (component_desc t) bs v"
  using agg
  by (simp add: ti_pad_combine_def Let_def field_update_extend_ti padding_desc_def)


lemma (in c_type) field_update_ti_typ_pad_combine:
  fixes acc:: "'s  'a"
  assumes agg: "aggregate t"
  shows "field_update (component_desc (ti_typ_pad_combine ft acc upd algn fn t)) bs v =
         (upd o xfrom_bytes)  (drop (field_sz (component_desc t) + padup (max (2 ^ algn) (align_of TYPE('a))) (size_td t)) bs)
           (field_update (component_desc t) bs v)"
  using agg
  apply (clarsimp simp add: ti_typ_pad_combine_def Let_def field_update_ti_pad_combine field_update_ti_typ_combine)
  apply (clarsimp simp add: ti_pad_combine_def field_update_extend_ti Let_def field_sz_extend_ti padding_desc_def)
  done

lemma field_update_final_pad:
  assumes agg: "aggregate t"
  shows "field_update (component_desc (final_pad algn t)) bs v =
           field_update (component_desc t) bs v"
  using agg
  by (simp add: final_pad_def field_update_ti_pad_combine Let_def)

lemma set_toplevel_field_descs_extend_ti:
"set (toplevel_field_descs (extend_ti t ft algn fn d))  insert d (set (toplevel_field_descs t))"
  apply (cases t)
  subgoal for x1 st n
    apply (cases st)
     apply simp
    subgoal for fs
      apply (cases fs)
       apply simp
      subgoal for f fs'
        apply simp
        done
      done
    done
  done

lemma set_toplevel_field_descs_extend_ti_aggregate:
"aggregate t  set (toplevel_field_descs (extend_ti t ft algn fn d)) = insert d (set (toplevel_field_descs t))"
  apply (cases t)
  subgoal for x1 st n
    apply (cases st)
     apply simp
    subgoal for fs
      apply (cases fs)
       apply simp
      subgoal for f fs'
        apply simp
        done
      done
    done
  done

lemma (in c_type) set_toplevel_field_descs_ti_typ_combine:
"set (toplevel_field_descs (ti_typ_combine ft (acc::'b  'a) upd algn fn t)) 
 insert field_access = xto_bytes  acc, field_update = upd  xfrom_bytes, field_sz = size_of TYPE('a)
 (set (toplevel_field_descs t))"
  apply (simp add: ti_typ_combine_def)
  apply (rule set_toplevel_field_descs_extend_ti)
  done

lemma (in c_type) set_toplevel_field_descs_ti_typ_combine_aggregate:
  fixes acc::"'s  'a"
  assumes agg: "aggregate t"
  shows "set (toplevel_field_descs (ti_typ_combine ft acc upd algn fn t)) =
         insert field_access = xto_bytes  acc, field_update = upd  xfrom_bytes, field_sz = size_of TYPE('a)
         (set (toplevel_field_descs t))"
  using agg
  apply (simp add: ti_typ_combine_def)
  apply (rule set_toplevel_field_descs_extend_ti_aggregate)
  apply simp
  done

lemma set_field_descs_extend_ti_aggregate:
"aggregate t  set (field_descs (extend_ti t ft algn fn d)) = insert d (set (field_descs ft)  set (field_descs t))"
  apply (cases t)
  subgoal for x1 st n
    apply (cases st)
     apply simp
    subgoal for fs
      apply (cases fs)
       apply simp
      subgoal for f fs'
        apply auto
        done
      done
    done
  done

lemma (in c_type) set_field_descs_ti_typ_combine_aggregate:
  fixes acc::"'s  'a"
  assumes agg: "aggregate t"
  shows "set (field_descs (ti_typ_combine ft acc upd algn fn t)) =
           insert field_access = xto_bytes  acc, field_update = upd  xfrom_bytes, field_sz = size_of TYPE('a)
           (set (field_descs (adjust_ti (typ_info_t TYPE('a)) acc upd))  set (field_descs t))"
  using agg
  apply (simp add: ti_typ_combine_def)
  apply (simp add: set_field_descs_extend_ti_aggregate)
  done


locale padding=
  fixes d::"'a field_desc"
  assumes independent: "field_desc_independent acc upd {d}"


lemma pad_is_padding: "padding (padding_desc n)"
  unfolding padding_desc_def
  apply (rule padding.intro)
  apply (rule field_desc_independent.intro)
    apply (auto simp add: fu_commutes_def)
  done

definition PAD::"'a field_desc set" where "PAD = {d. padding d}"

lemma in_PAD_iff[iff]: "d  PAD  (padding d)" by (auto simp add: PAD_def)

lemma (in c_type) set_toplevel_field_descs_ti_pad_combine_aggregate:
  fixes acc::"'s  'a"
  assumes agg: "aggregate t"
  shows "set (toplevel_field_descs (ti_pad_combine n t))  PAD =
         set (toplevel_field_descs t)  PAD"
  using agg
  by (auto simp add: ti_pad_combine_def Let_def set_toplevel_field_descs_extend_ti_aggregate
      pad_is_padding)

lemma (in c_type) set_toplevel_field_descs_ti_typ_pad_combine_aggregate:
  fixes acc::"'s  'a"
  assumes agg: "aggregate t"
  shows "set (toplevel_field_descs (ti_typ_pad_combine ft acc upd algn fn t))  PAD  =
           insert field_access = xto_bytes  acc, field_update = upd  xfrom_bytes, field_sz = size_of TYPE('a)
           ((set (toplevel_field_descs t))  PAD) "
  using agg
  apply (simp add: ti_typ_pad_combine_def Let_def)
  apply (cases "0 < padup (max (2 ^ algn) (align_of TYPE('a))) (size_td t)")
   apply clarsimp
   using set_toplevel_field_descs_ti_pad_combine_aggregate [OF agg, of  "(padup (max (2 ^ algn) (align_of TYPE('a))) (size_td t))"]
      set_toplevel_field_descs_ti_typ_combine_aggregate [OF aggregate_ti_pad_combine [of "(padup (max (2 ^ algn) (align_of TYPE('a))) (size_td t))" t], of ft acc upd algn fn]
   apply clarsimp
  apply (simp add: set_toplevel_field_descs_ti_typ_combine_aggregate)
  done

lemma toplevel_field_descs_map_align[simp]: "toplevel_field_descs (map_align f t) = toplevel_field_descs t"
  by (cases t) simp

lemma set_toplevel_field_descs_final_pad_aggregate:
  assumes agg: "aggregate t"
  shows "set (toplevel_field_descs (final_pad algn t))  PAD =
         set (toplevel_field_descs t)  PAD"
  using agg
  by (auto simp add: final_pad_def Let_def set_toplevel_field_descs_ti_pad_combine_aggregate)

lemma set_toplevel_field_descs_empty_typ_info: "set (toplevel_field_descs (empty_typ_info algn n)) = {}"
  by (simp add: empty_typ_info_def)

lemmas set_toplevel_field_descs_combinator_simps =
  set_toplevel_field_descs_empty_typ_info
  set_toplevel_field_descs_ti_typ_combine_aggregate
  set_toplevel_field_descs_ti_typ_pad_combine_aggregate
  set_toplevel_field_descs_final_pad_aggregate

lemma field_descs_independent_PAD:
"field_desc_independent acc upd (D  PAD) = field_desc_independent acc upd D"
  by (auto simp add: field_desc_independent_def padding_def)


lemma field_desc_independent_PAD_expand:
"field_desc_independent acc upd (D  PAD)  field_desc_independent acc upd D"
  by (simp add:  field_descs_independent_PAD)

lemma field_desc_independent_PAD_collapse:
"field_desc_independent acc upd D  field_desc_independent acc upd (D  PAD)"
  by (simp add:  field_descs_independent_PAD)

lemma insert_union_out: "insert d (X  Y) = insert d X  Y"
  by blast


lemmas field_sz_typ_combinators_simps =
  field_sz_final_pad
  field_sz_ti_typ_pad_combine
  field_sz_ti_typ_combine
  field_sz_empty_typ_info

lemmas field_update_typ_combinators_simps =
  field_update_final_pad
  field_update_ti_typ_pad_combine
  field_update_ti_typ_combine
  field_update_empty_typ_info

lemma aggregate_map_align[simp]: "aggregate (map_align f t) = aggregate t"
  by (cases t) simp

lemma aggregate_final_pad[simp]: "aggregate t  aggregate (final_pad algn t)"
  by (simp add: final_pad_def Let_def)

lemmas aggregate_typ_combinators_simps =
  aggregate_empty_typ_info
  aggregate_ti_pad_combine
  aggregate_ti_typ_pad_combine
  aggregate_final_pad



lemma wf_padding_empty_typ_info: "wf_padding (empty_typ_info algn tn)"
  by (simp add: empty_typ_info_def)

lemma is_padding_tag_padding_tag[simp]: "is_padding_tag (padding_tag n)"
  by (simp add: is_padding_tag_def padding_tag_def)

lemma is_padding_tag_pad_typ[simp]: "is_padding_tag (TypDesc 0 (TypScalar n 0 (padding_desc n)) ''!pad_typ'')"
  by (simp add: is_padding_tag_def padding_tag_def)

lemma wf_padding_padding_tag: "wf_padding (padding_tag n)"
  by (simp add: padding_tag_def)

lemma wf_padding_tuple_padI:
  "is_padding_tag s   wf_padding_tuple (DTuple s (CHR ''!''#xs) d)"
  by (auto simp add: is_padding_tag_def wf_padding_padding_tag)

lemma wf_padding_tuple_no_padI:
  "¬ padding_field_name fn  wf_padding s  wf_padding_tuple (DTuple s fn d)"
  by (simp)

lemma wf_padding_extend_ti:
  fixes
  t :: "'a xtyp_info" and
  st :: "'a xtyp_info_struct" and
  ts :: "'a xtyp_info_tuple list" and
  x :: "'a xtyp_info_tuple"
  shows
"wf_padding t  wf_padding_tuple (DTuple s fn d) 
    wf_padding (extend_ti t s n fn d)"

"wf_padding_struct st  wf_padding_tuple (DTuple s fn d) 
    wf_padding_struct (extend_ti_struct st s fn d)"

"wf_padding_list ts  wf_padding_tuple (DTuple s fn d) 
   wf_padding_list (ts @ [DTuple s fn d])"

"wf_padding_tuple x  wf_padding_tuple x"
  by (induct t and st and ts and x) auto

lemma is_padding_tag_update_desc: "is_padding_tag t 
      (x. upd (acc x) x = x) 
       is_padding_tag
        (map_td (λn algn. update_desc acc upd) (update_desc acc upd) t)"
  by (auto simp add: is_padding_tag_def padding_tag_def padding_desc_def update_desc_def fun_eq_iff)


lemma wf_padding_adjust_ti:
  fixes
  t :: "'a xtyp_info" and
  st :: "'a xtyp_info_struct" and
  ts :: "'a xtyp_info_tuple list" and
  x :: "'a xtyp_info_tuple"
assumes upd_acc_id: "(x. upd (acc x) x = x)"
  shows
"wf_padding t 
  wf_padding (map_td (λn algn. update_desc acc upd) (update_desc acc upd) t)"

"wf_padding_struct st 
  wf_padding_struct (map_td_struct (λn algn. update_desc acc upd) (update_desc acc upd) st)"

"wf_padding_list ts 
  wf_padding_list (map_td_list (λn algn. update_desc acc upd) (update_desc acc upd) ts)"

"wf_padding_tuple x 
  wf_padding_tuple (map_td_tuple (λn algn. update_desc acc upd) (update_desc acc upd) x)"
  apply  (induct t and st and ts and x)
  by (auto simp add: is_padding_tag_update_desc upd_acc_id)


lemma wf_padding_ti_pad_combine: "wf_padding t  wf_padding (ti_pad_combine n t)"
  by (simp add: ti_pad_combine_def Let_def wf_padding_extend_ti(1) )

lemma (in c_type) wf_padding_ti_typ_combine:
"wf_padding t  wf_padding (typ_info_t TYPE('a))  (xs. fn  CHR ''!''#xs)  (x. upd (acc x) x = x) 
 wf_padding (ti_typ_combine (TYPE('a)) acc upd algn fn t)"
  apply (simp add: ti_typ_combine_def Let_def)
  apply (rule wf_padding_extend_ti(1))
   apply assumption
  apply (simp add: adjust_ti_def wf_padding_adjust_ti(1) padding_field_name_def)
  done

lemma (in c_type) wf_padding_ti_typ_pad_combine:
"wf_padding t  wf_padding (typ_info_t TYPE('a))  (xs. fn  CHR ''!''#xs)  (x. upd (acc x) x = x) 
 wf_padding (ti_typ_pad_combine (TYPE('a)) acc upd algn fn t)"
  by (simp add: ti_typ_pad_combine_def wf_padding_ti_typ_combine wf_padding_ti_pad_combine Let_def)

lemma wf_padding_map_align: "wf_padding t  wf_padding (map_align f t)"
  by (cases t) (simp add: map_align_def)

lemma wf_padding_final_pad: "wf_padding t  wf_padding (final_pad n t)"
  by (simp add: final_pad_def wf_padding_ti_pad_combine Let_def wf_padding_map_align)

lemmas wf_padding_combinator_simps =
  wf_padding_empty_typ_info
  wf_padding_final_pad
  wf_padding_ti_typ_pad_combine
  wf_padding_ti_typ_combine


end