Theory IICF_Impl_Heapmap
section ‹Implementation of Heaps by Arrays›
theory IICF_Impl_Heapmap
imports 
  IICF_Abs_Heapmap 
  "../IICF_Array" 
  "../IICF_Array_List" 
  "../IICF_Array_Map_Total" 
  "../IICF_Indexed_Array_List"
begin
    
  locale hm_impl = hmstruct prio for prio :: "'e ⇒ 'p::linorder" +
    fixes prio_assn :: "'p ⇒ 'pi::llvm_rep ⇒ assn"
      and elem_assn :: "'e ⇒ 'ei::llvm_rep ⇒ assn"
      and prio_impl le_prio_impl lt_prio_impl
      and ltype :: "'l::len2 itself"
    assumes prio_is_pure[safe_constraint_rules]: "is_pure prio_assn"
    assumes elem_is_pure[safe_constraint_rules]: "is_pure elem_assn"  
    assumes prio_impl_refine[sepref_fr_rules]: "(prio_impl, RETURN o prio)∈elem_assn⇧k →⇩a prio_assn"
    assumes le_prio_impl_refine[sepref_fr_rules]: 
      "(uncurry le_prio_impl, uncurry (RETURN oo (≤))) ∈ prio_assn⇧k *⇩a prio_assn⇧k →⇩a bool1_assn"
    assumes lt_prio_impl_refine[sepref_fr_rules]: 
      "(uncurry lt_prio_impl, uncurry (RETURN oo (<))) ∈ prio_assn⇧k *⇩a prio_assn⇧k →⇩a bool1_assn"
      
  begin
    context
      fixes N :: nat
    begin
    abbreviation "idx_assn ≡ snatb_assn' TYPE('l) N"
    abbreviation "idx1_assn ≡ snatb_assn' TYPE('l) (Suc N)"
    sepref_register prio
    sepref_register "(≤) :: 'p ⇒ 'p ⇒ bool"
    sepref_register "(<) :: 'p ⇒ 'p ⇒ bool"
    
    lemmas [sepref_frame_free_rules] = 
      mk_free_is_pure[OF prio_is_pure]
      mk_free_is_pure[OF elem_is_pure]
    
    definition "hm2_assn ≡ b_assn (ial_assn' TYPE('l) N ×⇩a amt_assn elem_assn N) (λ_. 4<LENGTH('l) ∧ N<max_snat LENGTH('l))"
      
    lemma hm2_assn_rdomp_boundsI: "rdomp (hm2_assn) (ag, bq) ⟹ 4<LENGTH('l) ∧ N<max_snat LENGTH('l)"
      unfolding hm2_assn_def by auto
    
    
    find_theorems amt_assn
    
    sepref_definition hm_append_impl is "uncurry2 hm_append_op"
      :: "hm2_assn⇧d*⇩aidx_assn⇧k*⇩aelem_assn⇧k →⇩a hm2_assn"
      apply (rule hfref_with_rdomI)
      unfolding hm_append_op_def hm2_assn_def
      by sepref
      
    lemmas [sepref_fr_rules] = hm_append_impl.refine
      
    sepref_definition hm_length_impl is "RETURN o hm_length" :: "hm2_assn⇧k →⇩a snatb_assn' TYPE('l) (N+1)"
      apply (rule hfref_with_rdomI)
      unfolding hm_length_def hm2_assn_def
      by sepref
      
    lemmas [sepref_fr_rules] = hm_length_impl.refine
      
    term hm2_assn  
    sepref_register hm_key_of_op  
    sepref_definition hm_key_of_impl is "uncurry hm_key_of_op" :: "hm2_assn⇧k *⇩a idx1_assn⇧d →⇩a idx_assn"
      apply (rule hfref_with_rdomI)
      unfolding hm_key_of_op_def hm2_assn_def
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = hm_key_of_impl.refine
      
    
    definition "hm_the_lookup_op' k hm ≡ do {
      let (pq,ml) = hm;
      v ← mop_map_the_lookup k ml;
      RETURN v
    }"
    lemma hm_the_lookup_op'_refine: 
      "(hm_the_lookup_op', hm_the_lookup_op) ∈ nat_rel → Id → ⟨Id⟩nres_rel"
      apply (intro fun_relI nres_relI)
      unfolding hm_the_lookup_op'_def hm_the_lookup_op_def
      apply refine_vcg
      apply (auto)
      apply (auto simp: heapmap_α_def hmr_invar_def restrict_map_def split: if_split_asm)
      done
    sepref_definition hm_the_lookup_impl is "uncurry hm_the_lookup_op'" :: "idx_assn⇧k*⇩ahm2_assn⇧k →⇩a elem_assn"
      apply (rule hfref_with_rdomI)
      unfolding hm_the_lookup_op'_def hm2_assn_def Let_def
      by sepref
    lemmas hm_the_lookup_impl_refine[sepref_fr_rules] 
      = hm_the_lookup_impl.refine[FCOMP hm_the_lookup_op'_refine]
    sepref_definition hm_val_of_impl is "uncurry hm_val_of_op" :: "hm2_assn⇧k*⇩aidx1_assn⇧k →⇩a elem_assn"  
      unfolding hm_val_of_op_def
      by sepref
    lemmas [sepref_fr_rules] = hm_val_of_impl.refine
      
    sepref_register hm_prio_of_op
    sepref_definition hm_prio_of_impl is "uncurry (PR_CONST hm_prio_of_op)" :: "hm2_assn⇧k*⇩aidx1_assn⇧k →⇩a prio_assn"  
      unfolding hm_prio_of_op_def PR_CONST_def
      by sepref
    lemmas [sepref_fr_rules] = hm_prio_of_impl.refine
      
    definition "parent_valid h i ≡ hm_valid h (h.parent i)"
    definition "parent_valid' h i ≡ i>(1::nat)"
    
    lemma valid_parent_pat[def_pat_rules]: "hm_valid$h$(h.parent$i) ≡ parent_valid$h$i"
      unfolding parent_valid_def autoref_tag_defs by simp
    
    lemma parent_valid'_refine: "(uncurry parent_valid',uncurry parent_valid) ∈ [λ(h,i). hm_valid h i]⇩f Id×⇩rId→Id"
      apply rule
      unfolding hm_valid_def parent_valid_def parent_valid'_def hm_length_def h.parent_def 
      by auto
    
    sepref_definition parent_valid_impl is "uncurry (RETURN oo parent_valid')" :: "hm2_assn⇧k*⇩aidx1_assn⇧d →⇩a bool1_assn" 
      unfolding parent_valid'_def
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = parent_valid_impl.refine[FCOMP parent_valid'_refine]
    
    sepref_definition hm_exch_impl is "uncurry2 hm_exch_op" :: "hm2_assn⇧d*⇩aidx1_assn⇧d*⇩aidx1_assn⇧d →⇩a hm2_assn"
      apply (rule hfref_with_rdomI)
      unfolding hm_exch_op_def hm2_assn_def
      apply (annot_snat_const "TYPE('l)")
      supply [simp] = hm_valid_def
      by sepref
    lemmas [sepref_fr_rules] = hm_exch_impl.refine
    
    sepref_definition parent_impl is "RETURN o h.parent" :: "[λ_. 4<LENGTH('l)]⇩aidx1_assn⇧d → idx1_assn"
      unfolding h.parent_def
      apply (rule hfref_bassn_resI)
      subgoal by auto
      apply (annot_snat_const "TYPE('l)")
      by sepref
      
    lemmas [sepref_fr_rules] = parent_impl.refine    
    
    find_theorems hm_swim_op
    sepref_register h.parent hm_exch_op
    
        
    lemma workaround_invalid_recombine_pure3: "is_pure B ⟹ hn_ctxt (invalid_assn A ×⇩a invalid_assn B) ax px ⊢ hn_invalid (A ×⇩a B) ax px"
      unfolding hn_ctxt_def invalid_assn_def prod_assn_def entails_def
      by (auto split: prod.split elim!: is_pureE 
        simp: sep_algebra_simps pure_part_pure_conj_eq)
      
    
    find_theorems is_pure b_assn  
    
    sepref_register hm_swim_op
    sepref_definition hm_swim_impl is "uncurry (PR_CONST hm_swim_op)" :: "hm2_assn⇧d*⇩aidx1_assn⇧k →⇩a hm2_assn"
      unfolding hm_swim_op_def PR_CONST_def
      
      supply X[sepref_frame_match_rules] = workaround_invalid_recombine_pure3[where B="snatb_assn _", simplified]
      supply [simp] = hm2_assn_rdomp_boundsI
      by sepref
    lemmas [sepref_fr_rules] = hm_swim_impl.refine
    
    sepref_register hm_insert_op
    sepref_definition hm_insert_impl is "uncurry2 (PR_CONST hm_insert_op)" 
      :: "idx_assn⇧k*⇩aelem_assn⇧k*⇩ahm2_assn⇧d →⇩a hm2_assn"
      unfolding hm_insert_op_def PR_CONST_def
      by sepref
    lemmas [sepref_fr_rules] = hm_insert_impl.refine
    
    lemma rewr_2kleN: "2*k ≤ n ⟷ k ≤ n div 2" for k :: nat by auto
      
    sepref_definition hm_has_child_impl is "uncurry (RETURN oo hm_has_child_op)" :: "hm2_assn⇧k*⇩aidx1_assn⇧d →⇩a bool1_assn"
      unfolding hm_has_child_op_def
      apply (rewrite rewr_2kleN)
      supply [simp,dest] = hm2_assn_rdomp_boundsI
      apply (annot_snat_const "TYPE('l)")
      by sepref
      
    lemmas [sepref_fr_rules] = hm_has_child_impl.refine    
    sepref_definition hm_left_child_impl is "RETURN o hm_left_child_op" :: "[λi. 2*i≤N ∧ N<max_snat LENGTH('l) ∧ 4<LENGTH('l)]⇩a idx1_assn⇧d → idx1_assn"
      unfolding hm_left_child_op_def
      apply (rule hfref_bassn_resI)
      subgoal by auto
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = hm_left_child_impl.refine  
    lemma rewr_kp1len: "k+1 ≤ n ⟷ k<(n::nat)" by auto
    
    sepref_definition hm_has_next_child_impl is "uncurry (RETURN oo hm_has_next_child_op)" :: "hm2_assn⇧k*⇩aidx1_assn⇧d →⇩a bool1_assn"
      unfolding hm_has_next_child_op_def
      apply (rewrite rewr_kp1len)
      by sepref
    lemmas [sepref_fr_rules] = hm_has_next_child_impl.refine    
    sepref_definition hm_next_child_impl is "RETURN o hm_next_child_op" :: "[λi. i<N ∧ N<max_snat LENGTH('l) ∧ 4<LENGTH('l)]⇩a idx1_assn⇧d → idx1_assn"
      unfolding hm_next_child_op_def
      apply (rule hfref_bassn_resI)
      subgoal by auto
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = hm_next_child_impl.refine  
    
    
    lemma sink_sepref_aux2: "⟦hm_has_child_op (ag, bq) a2'; rdomp hm2_assn (ag, bq)⟧
       ⟹ 2 * a2' ≤ N"   
      unfolding hm_has_child_op_def hm2_assn_def hm_length_def 
      by sepref_bounds
       
    lemma sink_sepref_aux3: "⟦hm_has_next_child_op (ag, bq) i; rdomp hm2_assn (ag, bq)⟧ ⟹ i<N" 
      unfolding hm_has_next_child_op_def hm2_assn_def hm_length_def 
      by sepref_bounds
       
    sepref_register hm_sink_op
    sepref_definition hm_sink_impl is "uncurry (PR_CONST hm_sink_op)" :: "hm2_assn⇧d*⇩aidx1_assn⇧k →⇩a hm2_assn"
      unfolding hm_sink_op_def PR_CONST_def
      supply [simp] = hm_length_def
      supply [simp] = sink_sepref_aux2 sink_sepref_aux3
      supply X[sepref_frame_match_rules] = workaround_invalid_recombine_pure3[where B="snatb_assn _", simplified]
      supply [simp,dest] = hm2_assn_rdomp_boundsI
      by sepref
    lemmas [sepref_fr_rules] = hm_sink_impl.refine
      
    sepref_register hm_repair_op  
    sepref_definition hm_repair_impl is "uncurry (PR_CONST hm_repair_op)" :: "hm2_assn⇧d*⇩aidx1_assn⇧k →⇩a hm2_assn"
      unfolding hm_repair_op_def PR_CONST_def
      by sepref
    lemmas [sepref_fr_rules] = hm_repair_impl.refine
      
    sepref_definition hm_is_empty_impl is "hm_is_empty_op" :: "hm2_assn⇧k →⇩a bool1_assn"
      unfolding hm_is_empty_op_def
      apply (annot_snat_const "TYPE('l)")
      by sepref
    
      
      
    sepref_register hm_contains_key_op
    sepref_definition hm_contains_key_impl is "uncurry (PR_CONST hm_contains_key_op)" :: "idx_assn⇧k *⇩a hm2_assn⇧k →⇩a bool1_assn"
      apply (rule hfref_with_rdomI)
      unfolding hm_contains_key_op_def hm2_assn_def PR_CONST_def
      by sepref
    lemmas [sepref_fr_rules] = hm_contains_key_impl.refine  
      
    lemma hm_index_impl_aux1: "⟦b ∈ set a1'; rdomp (ial_assn N) a1'; N<max_snat LENGTH('l)⟧
       ⟹ Suc (index a1' b) < max_snat LENGTH('l)"  
      apply sepref_bounds
      by (meson index_less less_trans_Suc)
      
    sepref_definition hm_index_impl is "uncurry hm_index_op" :: "hm2_assn⇧k*⇩aidx_assn⇧d→⇩aidx1_assn"
      unfolding hm_index_op_def hm2_assn_def
      apply (rule hfref_bassn_resI)
      subgoal 
        apply (clarsimp simp: uncurry_def) 
        apply refine_vcg 
        apply sepref_bounds
        by (auto simp: heapmap_α_def restrict_map_eq)
      supply [simp] = heapmap_α_def restrict_map_eq hm_index_impl_aux1
      apply (rule hfref_with_rdomI)
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = hm_index_impl.refine  
      
    term hm_update_op
    sepref_definition hm_update_impl is "uncurry2 hm_update_op" :: "hm2_assn⇧d*⇩aidx1_assn⇧d*⇩aelem_assn⇧k →⇩a hm2_assn"
      unfolding hm_update_op_def hm2_assn_def
      apply (rule hfref_with_rdomI)
      supply [simp] = hm_valid_def
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = hm_update_impl.refine
    
    sepref_register hm_decrease_key_op
    sepref_definition hm_decrease_key_impl is "uncurry2 (PR_CONST hm_decrease_key_op)" :: "idx_assn⇧k *⇩a elem_assn⇧k *⇩a hm2_assn⇧d →⇩a hm2_assn "
      unfolding hm_decrease_key_op_def PR_CONST_def
      by sepref
    lemmas [sepref_fr_rules] = hm_decrease_key_impl.refine
          
    sepref_register hm_increase_key_op
    sepref_definition hm_increase_key_impl is "uncurry2 (PR_CONST hm_increase_key_op)" :: "idx_assn⇧k *⇩a elem_assn⇧k *⇩a hm2_assn⇧d →⇩a hm2_assn "
      unfolding hm_increase_key_op_def PR_CONST_def
      by sepref
    lemmas [sepref_fr_rules] = hm_increase_key_impl.refine
    sepref_register hm_change_key_op
    sepref_definition hm_change_key_impl is "uncurry2 (PR_CONST hm_change_key_op)" :: "idx_assn⇧k *⇩a elem_assn⇧k *⇩a hm2_assn⇧d →⇩a hm2_assn "
      unfolding hm_change_key_op_def PR_CONST_def
      by sepref
    lemmas [sepref_fr_rules] = hm_change_key_impl.refine
        
    sepref_register hm_set_op
    sepref_definition hm_set_impl is "uncurry2 (PR_CONST hm_set_op)" :: "idx_assn⇧k*⇩aelem_assn⇧k*⇩ahm2_assn⇧d →⇩a hm2_assn"
      unfolding hm_set_op_def PR_CONST_def
      by sepref
    lemmas [sepref_fr_rules] = hm_set_impl.refine
          
    sepref_register hm_butlast_op  
    sepref_definition hm_butlast_impl is "hm_butlast_op" :: "hm2_assn⇧d →⇩a hm2_assn"
      unfolding hm_butlast_op_def hm2_assn_def
      apply (rule hfref_with_rdomI)
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = hm_butlast_impl.refine      
      
    lemma hm_pop_min_impl_aux1: 
      "⟦hm_valid (pq, m) (Suc 0); rdomp hm2_assn (pq, m)⟧ ⟹ 0<N"
      unfolding hm2_assn_def hm_valid_def hm_length_def
      by (cases pq; sepref_bounds)
      
    sepref_register hm_pop_min_op
    sepref_definition hm_pop_min_impl is "PR_CONST hm_pop_min_op" :: "hm2_assn⇧d →⇩a (idx_assn ×⇩a elem_assn) ×⇩a hm2_assn"
      unfolding hm_pop_min_op_def PR_CONST_def
      supply [simp] = hm_pop_min_impl_aux1
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = hm_pop_min_impl.refine      
    
    sepref_register hm_remove_op 
    sepref_definition hm_remove_impl is "uncurry (PR_CONST hm_remove_op)" :: "idx_assn⇧k *⇩a hm2_assn⇧d →⇩a hm2_assn"
      unfolding hm_remove_op_def PR_CONST_def
      
      apply (rewrite at "if ⌑≠_ then _ else _" fold_COPY)
      by sepref
    lemmas [sepref_fr_rules] = hm_remove_impl.refine
    
    sepref_register hm_peek_min_op
    sepref_definition hm_peek_min_impl is "hm_peek_min_op" :: "hm2_assn⇧k →⇩a idx_assn×⇩aelem_assn"
      unfolding hm_peek_min_op_def hm_kv_of_op_def
      supply [simp] = hm_pop_min_impl_aux1
      apply (annot_snat_const "TYPE('l)")
      by sepref
    lemmas [sepref_fr_rules] = hm_peek_min_impl.refine
    end
    
    
    sepref_decl_op hm_empty: "λ_::nat. op_map_empty" :: "nat_rel → ⟨K,V⟩map_rel" .
    
    context fixes N :: nat begin
      sepref_decl_op hm_empty_fixed: "op_hm_empty N" :: "⟨K,V⟩map_rel" .
    end
    
    lemma fold_custom_hm_empty:
      "Map.empty = op_hm_empty N"
      "RETURN Map.empty = mop_hm_empty N"
      "mop_map_empty = mop_hm_empty N"
      by auto
    
    lemma fold_custom_hm_empty_fixed:
      "Map.empty = op_hm_empty_fixed N"
      "RETURN Map.empty = mop_hm_empty_fixed N"
      "mop_map_empty = mop_hm_empty_fixed N"
      by auto
      
      
    term hm_empty_op   
    
    definition "hm_empty_op' N ≡ do { m←mop_amt_empty N; RETURN (op_ial_empty N,m) }"
    
    lemma hm_empty_op_N: "hm_empty_op' N = hm_empty_op"
      by (auto simp: hm_empty_op_def hm_empty_op'_def)
    lemma hm_empty_op'_aref: "(hm_empty_op', mop_hm_empty) ∈ nat_rel → ⟨heapmap_rel⟩nres_rel"  
      using hm_empty_op_aref by (auto simp: hm_empty_op_N)
          
      
    sepref_definition hm_empty_impl is "hm_empty_op'" :: "[λ_. 4<LENGTH('l)]⇩a (snat_assn' TYPE('l))⇧k →⇩d (λN. hm2_assn N)"
      unfolding hm_empty_op_def hm_empty_op'_def hm2_assn_def
      apply (rule hfref_with_rdomI)
      by sepref
      
    definition "hm12_assn N ≡ hrr_comp nat_rel (λN. hm2_assn N) (λ_. heapmap_rel) N"
    
    lemma hm12_assn_fold': "hr_comp (hm2_assn N) heapmap_rel = hm12_assn N"
      unfolding hm12_assn_def
      by auto
      
    lemma hm12_assn_fold'': "hrr_comp nat_rel (λN. hm2_assn N) (λ_. heapmap_rel) = (λN. hm12_assn N)"  
      unfolding hm12_assn_def
      by auto
    
    context 
      notes [fcomp_norm_unfold] = hm12_assn_def[symmetric] hm12_assn_fold' hm12_assn_fold''
    begin
    
      lemmas hm_empty_ref12 = hm_empty_impl.refine[FCOMP hm_empty_op'_aref]
      lemmas hm_insert_ref12 = hm_insert_impl.refine[unfolded PR_CONST_def, FCOMP hm_insert_op_aref]
      lemmas hm_is_empty_ref12 = hm_is_empty_impl.refine[FCOMP hm_is_empty_op_aref]
      lemmas hm_the_lookup_ref12 = hm_the_lookup_impl_refine[FCOMP hm_the_lookup_op_aref]
      lemmas hm_contains_key_ref12 = hm_contains_key_impl.refine[unfolded PR_CONST_def, FCOMP hm_contains_key_op_aref]
      lemmas hm_decrease_key_ref12 = hm_decrease_key_impl.refine[unfolded PR_CONST_def, FCOMP hm_decrease_key_op_aref]
      lemmas hm_increase_key_ref12 = hm_increase_key_impl.refine[unfolded PR_CONST_def, FCOMP hm_increase_key_op_aref]
      lemmas hm_change_key_ref12 = hm_change_key_impl.refine[unfolded PR_CONST_def, FCOMP hm_change_key_op_aref]
      lemmas hm_set_ref12 = hm_set_impl.refine[unfolded PR_CONST_def, FCOMP hm_set_op_aref]
      lemmas hm_pop_min_ref12 = hm_pop_min_impl.refine[unfolded PR_CONST_def, FCOMP hm_pop_min_op_aref]
      lemmas hm_remove_ref12 = hm_remove_impl.refine[unfolded PR_CONST_def, FCOMP hm_remove_op_aref]
      lemmas hm_peek_min_ref12 = hm_peek_min_impl.refine[FCOMP hm_peek_min_op_aref]
            
    end
    definition "hm_assn N ≡ hr_comp (hm12_assn N) (⟨nat_rel, Id⟩map_rel)"
    
    lemma hm_assn_fold': "hrr_comp nat_rel (λN. hm12_assn N) (λx. ⟨nat_rel, Id⟩map_rel) = (λN. hm_assn N)"
      by (auto simp: hm_assn_def fun_eq_iff)
    
    context
      notes [fcomp_norm_unfold] = hm_assn_def[symmetric] hm_assn_fold'
    begin
      
      
      sepref_decl_impl (ismop) hm_empty_ref12 
        uses mop_hm_empty.fref[where K=Id and V=Id] fixes 'l by parametricity simp
      
      context 
        fixes N :: nat and Ni :: "'l word"
        assumes Ni_ref: "(Ni,N)∈snat_rel' TYPE('l)"
      begin  
        lemma hm_empty_fixed_ref: 
          "(uncurry0 (hm_empty_impl Ni), uncurry0 (PR_CONST (mop_hm_empty_fixed N))) ∈ [λ_. 4 < LENGTH('l)]⇩a unit_assn⇧k → hm12_assn N"
          apply rule
          apply (drule hfrefD[OF hm_empty_ref12, of N Ni])
          using Ni_ref
          by (simp_all add: pure_def)
      
        sepref_decl_impl (ismop,no_register) hm_empty_fixed: hm_empty_fixed_ref
          uses mop_hm_empty_fixed.fref[where K=Id and V=Id] fixes 'l by parametricity simp
          
      end
        
      sepref_decl_impl (ismop) hm_insert_ref12 uses mop_map_update_new.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_is_empty_ref12 uses mop_map_is_empty.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_the_lookup_ref12 uses mop_map_the_lookup.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_contains_key_ref12 uses mop_map_contains_key.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_decrease_key_ref12 uses mop_pm_decrease_key.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_increase_key_ref12 uses mop_pm_increase_key.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_change_key_ref12 uses mop_map_update_ex.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_set_ref12 uses mop_map_update.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_pop_min_ref12 uses mop_pm_pop_min.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_remove_ref12 uses mop_map_delete_ex.fref[where K=Id and V=Id] .
      sepref_decl_impl (ismop) hm_peek_min_ref12 uses mop_pm_peek_min.fref[where K=Id and V=Id] .
    end    
        
  end