Theory Pairing_Heaps_Impl_LLVM

theory Pairing_Heaps_Impl_LLVM
  imports Pairing_Heap_LLVM.Pairing_Heaps_Impl IsaSAT_Literals_LLVM
begin

type_synonym hp_assn = 32 word ptr × 32 word ptr × 32 word ptr × 32 word ptr × 64 word ptr × 32 word

definition hp_assn :: _  hp_assn  assn where
  hp_assn  (IICF_Array.array_assn atom.option_assn ×a
    IICF_Array.array_assn atom.option_assn ×a
    IICF_Array.array_assn atom.option_assn ×a
    IICF_Array.array_assn atom.option_assn ×a
    IICF_Array.array_assn uint64_nat_assn ×a atom.option_assn)

sepref_def mop_hp_read_prev_imp_code
  is uncurry mop_hp_read_prev_imp
  :: atom_assnk *a hp_assnk a atom.option_assn
  unfolding mop_hp_read_prev_imp_def hp_assn_def
  apply (rewrite at _!  value_of_atm_def[symmetric])
  apply (rewrite in _ !  annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_def mop_hp_read_nxt_imp_code
  is uncurry mop_hp_read_nxt_imp
  :: atom_assnk *a hp_assnk a atom.option_assn
  unfolding mop_hp_read_nxt_imp_def hp_assn_def
  apply (rewrite at _!  value_of_atm_def[symmetric])
  apply (rewrite in _ !  annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_def mop_hp_read_parent_imp_code
  is uncurry mop_hp_read_parent_imp
  :: atom_assnk *a hp_assnk a atom.option_assn
  unfolding mop_hp_read_parent_imp_def hp_assn_def
  apply (rewrite at _!  value_of_atm_def[symmetric])
  apply (rewrite in _ !  annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_def mop_hp_read_child_imp_code
  is uncurry mop_hp_read_child_imp
  :: atom_assnk *a hp_assnk a atom.option_assn
  unfolding mop_hp_read_child_imp_def hp_assn_def
  apply (rewrite at _!  value_of_atm_def[symmetric])
  apply (rewrite in _ !  annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_def mop_hp_read_score_imp_code
  is uncurry mop_hp_read_score_imp
  :: atom_assnk *a hp_assnk a uint64_nat_assn
  unfolding mop_hp_read_score_imp_def hp_assn_def
  apply (rewrite at _!  value_of_atm_def[symmetric])
  apply (rewrite in _ !  annot_unat_snat_upcast[where 'l=64])
  by sepref

lemma source_node_impl_alt_def:
  source_node_impl = (λ(prevs, nxts, parents, children, scores,i). i)
  by (auto intro!: ext)

sepref_def source_node_impl_code
  is (RETURN o source_node_impl)
  :: hp_assnk a atom.option_assn
  unfolding source_node_impl_alt_def hp_assn_def
  by sepref

lemma update_source_node_impl_alt_def:
  update_source_node_impl = (λi (prevs, nxts, parents, children, scores,_). (prevs, nxts, parents, children, scores, i))
  by (auto intro!: ext)

sepref_def update_source_node_impl_code
  is uncurry (RETURN oo update_source_node_impl)
  :: atom.option_assnk *a hp_assnd a hp_assn
  unfolding update_source_node_impl_alt_def hp_assn_def
  by sepref

sepref_def mop_hp_update_prev'_imp_code
  is uncurry2 mop_hp_update_prev'_imp
  :: atom_assnk *a atom.option_assnk *a hp_assnd a hp_assn
  unfolding mop_hp_update_prev'_imp_def hp_assn_def
  apply (rewrite at _[:=_] value_of_atm_def[symmetric])
  apply (rewrite in _ [:=_] annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_def mop_hp_update_child'_imp_code
  is uncurry2 mop_hp_update_child'_imp
  :: atom_assnk *a atom.option_assnk *a hp_assnd a hp_assn
  unfolding mop_hp_update_child'_imp_def hp_assn_def
  apply (rewrite at _[:=_] value_of_atm_def[symmetric])
  apply (rewrite in _ [:=_] annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_def mop_hp_update_nxt'_imp_code
  is uncurry2 mop_hp_update_nxt'_imp
  :: atom_assnk *a atom.option_assnk *a hp_assnd a hp_assn
  unfolding mop_hp_update_nxt'_imp_def hp_assn_def
  apply (rewrite at _[:=_] value_of_atm_def[symmetric])
  apply (rewrite in _ [:=_] annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_def mop_hp_update_parent'_imp_code
  is uncurry2 mop_hp_update_parent'_imp
  :: atom_assnk *a atom.option_assnk *a hp_assnd a hp_assn
  unfolding mop_hp_update_parent'_imp_def hp_assn_def
  apply (rewrite at _[:=_] value_of_atm_def[symmetric])
  apply (rewrite in _ [:=_] annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_def mop_hp_set_all_imp_code
  is uncurry6 mop_hp_set_all_imp
  ::  atom_assnk *a atom.option_assnk *a atom.option_assnk *a atom.option_assnk *a atom.option_assnk *a uint64_nat_assnk *a hp_assnd a hp_assn
  unfolding mop_hp_set_all_imp_def hp_assn_def
  apply (rewrite at _[:=_] value_of_atm_def[symmetric])
  apply (rewrite in _ [:=_] annot_unat_snat_upcast[where 'l=64])
  apply (rewrite at (_, _[:=_], _) value_of_atm_def[symmetric])
  apply (rewrite in (_, _ [:=_],_) annot_unat_snat_upcast[where 'l=64])
  apply (rewrite at (_, _, _[:=_], _) value_of_atm_def[symmetric])
  apply (rewrite in (_, _, _ [:=_],_) annot_unat_snat_upcast[where 'l=64])
  apply (rewrite at (_, _, _, _[:=_], _) value_of_atm_def[symmetric])
  apply (rewrite in (_, _, _, _ [:=_],_) annot_unat_snat_upcast[where 'l=64])
  apply (rewrite at (_, _, _, _, _[:=_], _) value_of_atm_def[symmetric])
  apply (rewrite in (_, _, _, _, _ [:=_],_) annot_unat_snat_upcast[where 'l=64])
  by sepref

sepref_register mop_hp_set_all_imp
  mop_hp_update_parent'_imp mop_hp_update_nxt'_imp mop_hp_update_child'_imp mop_hp_update_prev'_imp
  mop_hp_read_score_imp mop_hp_read_nxt_imp mop_hp_read_prev_imp mop_hp_read_parent_imp mop_hp_read_child_imp
  maybe_mop_hp_update_prev'_imp maybe_mop_hp_update_nxt'_imp maybe_mop_hp_update_child'_imp maybe_mop_hp_update_parent'_imp


sepref_def mop_hp_insert_impl_code
  is uncurry2 mop_hp_insert_impl
  :: atom_assnk *a uint64_nat_assnk *a hp_assnd a hp_assn
  unfolding mop_hp_insert_impl_def
    atom.fold_option
  by sepref

sepref_def maybe_mop_hp_update_prev'_imp_code
  is uncurry2 maybe_mop_hp_update_prev'_imp
  :: atom.option_assnk *a atom.option_assnk *a hp_assnd a hp_assn
  unfolding maybe_mop_hp_update_prev'_imp_def
    atom.fold_option
  by sepref

sepref_def maybe_mop_hp_update_nxt'_imp_code
  is uncurry2 maybe_mop_hp_update_nxt'_imp
  :: atom.option_assnk *a atom.option_assnk *a hp_assnd a hp_assn
  unfolding maybe_mop_hp_update_nxt'_imp_def
    atom.fold_option
  by sepref

sepref_def maybe_mop_hp_update_child'_imp_code
  is uncurry2 maybe_mop_hp_update_child'_imp
  :: atom.option_assnk *a atom.option_assnk *a hp_assnd a hp_assn
  unfolding maybe_mop_hp_update_child'_imp_def
    atom.fold_option
  by sepref

sepref_def maybe_mop_hp_update_parent'_imp_code
  is uncurry2 maybe_mop_hp_update_parent'_imp
  :: atom.option_assnk *a atom.option_assnk *a hp_assnd a hp_assn
  unfolding maybe_mop_hp_update_parent'_imp_def
    atom.fold_option
  by sepref

sepref_def mop_hp_link_imp_impl
  is uncurry2 mop_hp_link_imp
  :: atom_assnk *a atom_assnk *a hp_assnd a hp_assn ×a atom_assn
  unfolding mop_hp_link_imp_def
    atom.fold_option
  by sepref

sepref_register mop_hp_link_imp mop_vsids_pass1_imp  mop_vsids_pass2_imp mop_merge_pairs_imp
  mop_vsids_pop_min_impl mop_unroot_hp_tree

sepref_def mop_vsids_pass1_imp_code
  is uncurry mop_vsids_pass1_imp
  :: hp_assnd *a atom_assnk a hp_assn ×a atom_assn
  unfolding mop_vsids_pass1_imp_def
    atom.fold_option
  by sepref

sepref_def mop_vsids_pass2_imp_code
  is uncurry mop_vsids_pass2_imp
  :: hp_assnd *a atom_assnk a hp_assn
  unfolding mop_vsids_pass2_imp_def
    atom.fold_option
  by sepref

sepref_def mop_merge_pairs_imp_code
  is uncurry mop_merge_pairs_imp
  :: hp_assnd *a atom_assnk a hp_assn
  unfolding mop_merge_pairs_imp_def
  by sepref

sepref_def mop_vsids_pop_min_impl_code
  is mop_vsids_pop_min_impl
  :: hp_assnd a atom.option_assn ×a hp_assn
  unfolding mop_vsids_pop_min_impl_def
    atom.fold_option
  by sepref


definition mop_source_node_impl where
  "mop_source_node_impl = RETURN o source_node_impl"
sepref_register mop_source_node_impl

sepref_def mop_source_node_impl_code
  is mop_source_node_impl
  :: hp_assnk a atom.option_assn
  unfolding mop_source_node_impl_def
  by sepref

sepref_register
  "source_node_impl :: (nat,nat)pairing_heaps_imp  _"

hide_const (open) NEMonad.ASSERT NEMonad.RETURN NEMonad.SPEC
lemma mop_unroot_hp_tree_alt_def:
  mop_unroot_hp_tree arr h = do {
    a  mop_source_node_impl arr;
    nnext  mop_hp_read_nxt_imp h arr;
    parent  mop_hp_read_parent_imp h arr;
    prev  mop_hp_read_prev_imp h arr;
    if prev = None  parent = None  ¬(a  None  the a = h) then RETURN (update_source_node_impl None arr)
    else if a  None  the a = h then RETURN (update_source_node_impl None arr)
    else do {
      ASSERT (a  None);
      let a' = the a;
      arr   maybe_mop_hp_update_child'_imp parent nnext arr;
      arr   maybe_mop_hp_update_nxt'_imp prev nnext arr;
      arr   maybe_mop_hp_update_prev'_imp nnext prev arr;
      arr   maybe_mop_hp_update_parent'_imp nnext parent arr;

      arr   mop_hp_update_nxt'_imp h None arr;
      arr   mop_hp_update_prev'_imp h None arr;
      arr   mop_hp_update_parent'_imp h None arr;

      arr   mop_hp_update_nxt'_imp h (Some a') arr;
      arr   mop_hp_update_prev'_imp a' (Some h) arr;
      RETURN (update_source_node_impl None arr)
    }
}
   unfolding mop_unroot_hp_tree_def mop_source_node_impl_def
   by (cases source_node_impl arr)
    (auto intro!: bind_cong[OF refl] simp: Let_def)

sepref_def mop_unroot_hp_tree_code
  is uncurry (mop_unroot_hp_tree :: (nat,nat)pairing_heaps_imp  _)
  :: hp_assnd *a atom_assnk a hp_assn
  unfolding mop_unroot_hp_tree_alt_def
    atom.fold_option short_circuit_conv
  by sepref

sepref_def mop_hp_update_score_imp_code
  is uncurry2 mop_hp_update_score_imp
  :: atom_assnk *a uint64_nat_assnk *a hp_assnd a hp_assn
  unfolding mop_hp_update_score_imp_def hp_assn_def
  apply (rewrite at _[:=_] value_of_atm_def[symmetric])
  apply (rewrite in _ [:=_] annot_unat_snat_upcast[where 'l=64])
  by sepref


lemma Some_eq_not_None_sepref_id_work_around: Some h = a  (a  None  h = the a)
  by (cases a) auto

sepref_def mop_rescale_and_reroot_code
  is uncurry2 mop_rescale_and_reroot
  :: atom_assnk *a uint64_nat_assnk *a hp_assnd a hp_assn
  unfolding mop_rescale_and_reroot_def Some_eq_not_None_sepref_id_work_around
  unfolding atom.fold_option short_circuit_conv
  by sepref

sepref_def mop_hp_is_in_code
  is uncurry mop_hp_is_in
  :: atom_assnk *a hp_assnk a bool1_assn
  unfolding mop_hp_is_in_def Some_eq_not_None_sepref_id_work_around
  unfolding atom.fold_option short_circuit_conv
  by sepref

sepref_def mop_vsids_pop_min2_impl_code
  is mop_vsids_pop_min2_impl
  :: hp_assnd a atom_assn ×a hp_assn
  unfolding mop_vsids_pop_min2_impl_def
  unfolding atom.fold_option
  by sepref

lemma mop_hp_insert_impl_spec2:
  (uncurry2 mop_hp_insert_impl, uncurry2 hp_insert) 
    nat_rel ×f nat_rel ×f nat_reloption_rel,nat_reloption_relpairing_heaps_rel f
    nat_reloption_rel,nat_reloption_relpairing_heaps_relnres_rel
  by (intro frefI nres_relI) (auto intro!: mop_hp_insert_impl_spec[THEN order_trans])

lemma mop_rescale_and_reroot_spec2:
   (uncurry2 mop_rescale_and_reroot, uncurry2 rescale_and_reroot) 
    nat_rel ×f nat_rel ×f  nat_reloption_rel,nat_reloption_relpairing_heaps_rel f
    nat_reloption_rel,nat_reloption_relpairing_heaps_relnres_rel
  by (intro frefI nres_relI) (auto intro!: mop_rescale_and_reroot_spec[THEN order_trans])

lemma rescale_and_reroot_mop_prio_change_weight2:
  (uncurry2 rescale_and_reroot, uncurry2 (PR_CONST ACIDS.mop_prio_change_weight)) 
  nat_rel ×f  nat_rel ×f acids_encoded_hmrel f acids_encoded_hmrelnres_rel
  by (intro frefI nres_relI)
   (auto intro!: rescale_and_reroot_mop_prio_change_weight[THEN order_trans])

lemma mop_hp_is_in_spec2:
  (uncurry mop_hp_is_in, uncurry hp_is_in)  nat_rel ×f nat_reloption_rel, nat_reloption_relpairing_heaps_rel f bool_relnres_rel
  by (intro frefI nres_relI)
   (auto intro!: mop_hp_is_in_spec[THEN order_trans])

lemma vsids_pop_min2_mop_prio_pop_min2:
  (vsids_pop_min2, PR_CONST ACIDS.mop_prio_pop_min)  acids_encoded_hmrel f nat_rel ×r acids_encoded_hmrelnres_rel
  by (intro frefI nres_relI)
   (auto intro!: vsids_pop_min2_mop_prio_pop_min[THEN order_trans])

lemma mop_vsids_pop_min2_impl2:
  shows (mop_vsids_pop_min2_impl, vsids_pop_min2) 
    nat_reloption_rel,nat_reloption_relpairing_heaps_rel f
    nat_rel ×r nat_reloption_rel,nat_reloption_relpairing_heaps_relnres_rel
  by (intro frefI nres_relI)
   (auto intro!: mop_vsids_pop_min2_impl[THEN order_trans])

lemma mop_hp_read_score_imp_mop_hp_read_score2:
  (uncurry mop_hp_read_score_imp, uncurry mop_hp_read_score) 
  Id ×f nat_reloption_rel,nat_reloption_relpairing_heaps_rel f nat_relnres_rel
  by (intro frefI nres_relI)
   (auto intro!: mop_hp_read_score_imp_mop_hp_read_score[THEN order_trans])


thm mop_hp_read_score_imp_mop_hp_read_score
definition acids_assn :: _ where
  acids_assn = hr_comp (hr_comp hp_assn (nat_reloption_rel, nat_reloption_relpairing_heaps_rel))
              acids_encoded_hmrel

lemmas [fcomp_norm_unfold] = acids_assn_def[symmetric]

sepref_register ACIDS.mop_prio_change_weight ACIDS.mop_prio_insert
  ACIDS.mop_prio_pop_min ACIDS.mop_prio_is_in

lemmas [sepref_fr_rules] =
  mop_hp_insert_impl_code.refine[FCOMP mop_hp_insert_impl_spec2, FCOMP hp_insert_spec_mop_prio_insert2]
  mop_rescale_and_reroot_code.refine[FCOMP mop_rescale_and_reroot_spec2, FCOMP rescale_and_reroot_mop_prio_change_weight2]
  mop_hp_is_in_code.refine[FCOMP mop_hp_is_in_spec2, FCOMP hp_is_in_mop_prio_is_in2]
  mop_vsids_pop_min2_impl_code.refine[FCOMP mop_vsids_pop_min2_impl2, FCOMP vsids_pop_min2_mop_prio_pop_min2]
  mop_hp_read_score_imp_code.refine[FCOMP mop_hp_read_score_imp_mop_hp_read_score2, FCOMP mop_hp_read_score_mop_prio_old_weight2]

end