Theory TTreeImplCardinalitySafe

theory TTreeImplCardinalitySafe
imports TTreeImplCardinality TTreeAnalysisSpec CardinalityAnalysisSpec
begin

lemma pathsCard_paths_nxt:  "pathsCard (paths (nxt f x))  record_call x(pathsCard (paths f))"
  apply transfer
  apply (rule pathsCard_below)
  apply auto
  apply (erule below_trans[OF _ monofun_cfun_arg[OF paths_Card_above], rotated]) back
  apply (auto intro: fun_belowI simp add: record_call_simp two_pred_two_add_once)
  done

lemma pathsCards_none: "pathsCard (paths t) x = none  x  carrier t"
  by transfer (auto dest: pathCards_noneD)

lemma const_on_edom_disj: "const_on f S empty  edom f  S = {}"
  by (auto simp add: empty_is_bottom edom_def)

context TTreeAnalysisCarrier
begin
  lemma carrier_Fstack: "carrier (Fstack as S)  fv S"
    by (induction S rule: Fstack.induct)
       (auto simp add: empty_is_bottom[symmetric] carrier_Fexp dest!: subsetD[OF Aexp_edom])

  lemma carrier_FBinds: "carrier ((FBinds Γae) x)  fv Γ"
  apply (simp add: Texp.AnalBinds_lookup)
  apply (auto split: option.split simp add: empty_is_bottom[symmetric] )
  apply (case_tac "ae x")
  apply (auto simp add: empty_is_bottom[symmetric] carrier_Fexp dest!: subsetD[OF Aexp_edom])
  by (metis (poly_guards_query) contra_subsetD domA_from_set map_of_fv_subset map_of_SomeD option.sel)
end

context TTreeAnalysisSafe
begin

  sublocale CardinalityPrognosisShape prognosis
  proof
    fix Γ :: heap and ae ae' :: AEnv and u e S as
    assume "ae f|` domA Γ = ae' f|` domA Γ"
    from Texp.AnalBinds_cong[OF this]
    show "prognosis ae as u (Γ, e, S) = prognosis ae' as u (Γ, e, S)" by simp
  next
    fix ae as a Γ e S
    show "const_on (prognosis ae as a (Γ, e, S)) (ap S) many"
    proof
      fix x
      assume "x  ap S"
      hence "[x,x]  paths (Fstack as S)"
        by (induction S rule: Fstack.induct)
           (auto 4 4 intro: subsetD[OF both_contains_arg1] subsetD[OF both_contains_arg2] paths_Cons_nxt)
      hence "[x,x]  paths (Texp ea ⊗⊗ Fstack as S)"
        by (rule subsetD[OF both_contains_arg2])
      hence "[x,x]  paths (substitute (FBinds Γae) (thunks Γ) (Texp ea ⊗⊗ Fstack as S))" 
        by (rule subsetD[OF substitute_contains_arg])
      hence "pathCard [x,x] x  pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (Texp ea ⊗⊗ Fstack as S))) x"
        by (metis fun_belowD paths_Card_above)
      also have "pathCard [x,x] x = many"  by (auto simp add: pathCard_def)
      finally
      show "prognosis ae as a (Γ, e, S) x = many"
        by (auto intro: below_antisym)
    qed
  next
    fix Γ Δ :: heap and e :: exp and ae :: AEnv and as u S
    assume "map_of Γ = map_of Δ"
    hence "FBinds Γ = FBinds Δ" and "thunks Γ = thunks Δ" by (auto intro!: cfun_eqI  thunks_cong simp add: Texp.AnalBinds_lookup)
    thus "prognosis ae as u (Γ, e, S) = prognosis ae as u (Δ, e, S)"  by simp
  next
    fix Γ :: heap and e :: exp and ae :: AEnv and as u S x
    show "prognosis ae as u (Γ, e, S)  prognosis ae as u (Γ, e, Upd x # S)" by simp
  next
  fix Γ :: heap and e :: exp and ae :: AEnv and as a S x
  assume "ae x = "

  hence "FBinds (delete x Γ)ae = FBinds Γae" by (rule Texp.AnalBinds_delete_bot)
  moreover
  hence "((FBinds Γae) x) = " by (metis Texp.AnalBinds_delete_lookup)
  ultimately
  show "prognosis ae as a (Γ, e, S)  prognosis ae as a (delete x Γ, e, S)"
    by (simp add: substitute_T_delete empty_is_bottom)
  next
    fix ae as a Γ x S
    have "once  (pathCard [x]) x" by (simp add: two_add_simp)
    also have "pathCard [x]  pathsCard ({[],[x]})"
      by (rule paths_Card_above) simp
    also have " = pathsCard (paths (single x))" by simp
    also have "single x  (Texp (Var x)a)" by (rule Texp_Var)
    also have "  Texp (Var x)a ⊗⊗ Fstack as S" by (rule both_above_arg1)
    also have "  substitute  (FBinds Γae) (thunks Γ) (Texp (Var x)a ⊗⊗ Fstack as S)" by (rule substitute_above_arg)
    also have "pathsCard (paths ) x = prognosis ae as a (Γ, Var x, S) x" by simp
    finally
    show "once  prognosis ae as a (Γ, Var x, S) x"
      by this (rule cont2cont_fun, intro cont2cont)+
  qed

  sublocale CardinalityPrognosisApp prognosis
  proof
    fix ae as a Γ e x S
    have "Texp e(inca)  ⊗⊗ many_calls x ⊗⊗ Fstack as S = many_calls x  ⊗⊗ (Texp e)(inca) ⊗⊗ Fstack as S"
      by (metis both_assoc both_comm)
    thus "prognosis ae as (inca) (Γ, e, Arg x # S)  prognosis ae as a (Γ, App e x, S)"
      by simp (intro pathsCard_mono' paths_mono substitute_mono2' both_mono1' Texp_App)
  qed

  sublocale CardinalityPrognosisLam prognosis
  proof
    fix ae as a Γ e y x S
    have "Texp e[y::=x](preda)  many_calls x  ⊗⊗ Texp (Lam [y]. e)a"
      by (rule below_trans[OF Texp_subst both_mono2'[OF Texp_Lam]])
    moreover have "Texp (Lam [y]. e)a ⊗⊗ many_calls x ⊗⊗ Fstack as S = many_calls x  ⊗⊗ Texp (Lam [y]. e)a ⊗⊗ Fstack as S"
      by (metis both_assoc both_comm)
    ultimately  
    show "prognosis ae as (preda) (Γ, e[y::=x], S)  prognosis ae as a (Γ, Lam [y]. e, Arg x # S)"
      by simp (intro pathsCard_mono' paths_mono substitute_mono2' both_mono1')
  qed

  sublocale CardinalityPrognosisVar prognosis
  proof
    fix Γ :: heap and e :: exp and x :: var and ae :: AEnv and as u a S
    assume "map_of Γ x = Some e"
    assume "ae x = upu"

    assume "isVal e"
    hence "x  thunks Γ" using map_of Γ x = Some e by (metis thunksE)
    hence [simp]: "f_nxt (FBinds Γae) (thunks Γ) x = FBinds Γae" by (auto simp add: f_nxt_def)

    have "prognosis ae as u (Γ, e, S) = pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (Texp eu ⊗⊗ Fstack as S)))"
      by simp
    also have " = pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (nxt (single x) x ⊗⊗ Texp eu  ⊗⊗ Fstack as S)))"
      by simp
    also have " = pathsCard (paths (substitute (FBinds Γae) (thunks Γ) ((nxt (single x) x ⊗⊗ Fstack as S) ⊗⊗ Texp eu )))"
      by (metis both_assoc both_comm)
    also have "  pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (nxt (single x ⊗⊗ Fstack as S) x ⊗⊗ Texp eu)))"
      by (intro pathsCard_mono' paths_mono substitute_mono2' both_mono1'  nxt_both_left) simp
    also have " = pathsCard (paths (nxt (substitute (FBinds Γae) (thunks Γ) (single x ⊗⊗ Fstack as S)) x))"
      using map_of Γ x = Some e ae x = upu by (simp add: Texp.AnalBinds_lookup)
    also have "  record_call x (pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (single x ⊗⊗ Fstack as S))))"
      by (rule pathsCard_paths_nxt)
    also have "  record_call x (pathsCard (paths (substitute (FBinds Γae) (thunks Γ) ((Texp (Var x)a) ⊗⊗ Fstack as S))))"
      by (intro monofun_cfun_arg pathsCard_mono' paths_mono substitute_mono2' both_mono1' Texp_Var)
    also have " = record_call x (prognosis ae as a (Γ, Var x, S))"
      by simp
    finally
    show "prognosis ae as u (Γ, e, S)  record_call x(prognosis ae as a (Γ, Var x, S))" by this simp_all
  next
    fix Γ :: heap and e :: exp and x :: var and ae :: AEnv and as u a S
    assume "map_of Γ x = Some e"
    assume "ae x = upu"
    assume "¬ isVal e"
    hence "x  thunks Γ" using map_of Γ x = Some e by (metis thunksI)
    hence [simp]: "f_nxt (FBinds Γae) (thunks Γ) x = FBinds (delete x Γ)ae" 
      by (auto simp add: f_nxt_def Texp.AnalBinds_delete_to_fun_upd empty_is_bottom)

    have "prognosis ae as u (delete x Γ, e, Upd x # S) = pathsCard (paths (substitute (FBinds (delete x Γ)ae) (thunks (delete x Γ)) (Texp eu ⊗⊗ Fstack as S)))"
      by simp
    also have " = pathsCard (paths (substitute (FBinds (delete x Γ)ae) (thunks Γ) (Texp eu ⊗⊗ Fstack as S)))"
       by (rule arg_cong[OF substitute_cong_T]) (auto simp add: empty_is_bottom)
    also have " = pathsCard (paths (substitute (FBinds (delete x Γ)ae) (thunks Γ) (nxt (single x) x ⊗⊗ Texp eu  ⊗⊗ Fstack as S)))"
      by simp
    also have " = pathsCard (paths (substitute (FBinds (delete x Γ)ae) (thunks Γ) ((nxt (single x) x ⊗⊗ Fstack as S) ⊗⊗ Texp eu )))"
      by (metis both_assoc both_comm)
    also have "  pathsCard (paths (substitute (FBinds (delete x Γ)ae) (thunks Γ) (nxt (single x ⊗⊗ Fstack as S) x  ⊗⊗ Texp eu)))"
      by (intro pathsCard_mono' paths_mono substitute_mono2' both_mono1'  nxt_both_left) simp
    also have " = pathsCard (paths (nxt (substitute (FBinds Γae) (thunks Γ) (single x ⊗⊗ Fstack as S)) x))"
      using map_of Γ x = Some e ae x = upu by (simp add: Texp.AnalBinds_lookup)
    also have "  record_call x (pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (single x ⊗⊗ Fstack as S))))"
      by (rule pathsCard_paths_nxt)
    also have "  record_call x (pathsCard (paths (substitute (FBinds Γae) (thunks Γ) ((Texp (Var x)a) ⊗⊗ Fstack as S))))"
      by (intro monofun_cfun_arg pathsCard_mono' paths_mono substitute_mono2' both_mono1' Texp_Var)
    also have " = record_call x (prognosis ae as a (Γ, Var x, S))"
      by simp
    finally
    show "prognosis ae as u (delete x Γ, e, Upd x # S)  record_call x(prognosis ae as a (Γ, Var x, S))" by this simp_all
  next
    fix Γ :: heap and e :: exp and ae :: AEnv and  x :: var and as S
    assume "isVal e"
    hence "repeatable (Texp e0)" by (rule Fun_repeatable)

    assume [simp]: "x  domA Γ"

    have [simp]: "thunks ((x, e) # Γ) = thunks Γ" 
      using isVal e
      by (auto simp add: thunks_Cons dest: subsetD[OF thunks_domA])

    have "fup(Texp e)(ae x)  Texp e0" by (metis fup2 monofun_cfun_arg up_zero_top)
    hence "substitute ((FBinds Γae)(x := fup(Texp e)(ae x))) (thunks Γ) (Texp e0 ⊗⊗ Fstack as S)  substitute ((FBinds Γae)(x := Texp e0)) (thunks Γ) (Texp e0 ⊗⊗ Fstack as S)"
      by (intro substitute_mono1' fun_upd_mono below_refl monofun_cfun_arg)
    also have " = substitute (((FBinds Γae)(x := Texp e0))(x := empty)) (thunks Γ) (Texp e0 ⊗⊗ Fstack as S)"
      using repeatable (Texp e0) by (rule substitute_remove_anyways, simp)
    also have "((FBinds Γae)(x := Texp e0))(x := empty) = FBinds Γae"
      by (simp add: fun_upd_idem Texp.AnalBinds_not_there empty_is_bottom)
    finally
    show "prognosis ae as 0 ((x, e) # Γ, e, S)  prognosis ae as 0 (Γ, e, Upd x # S)"
      by (simp, intro pathsCard_mono' paths_mono)
  qed

  sublocale CardinalityPrognosisIfThenElse prognosis
  proof
    fix ae as Γ scrut e1 e2 S a
    have "Texp scrut0 ⊗⊗ (Texp e1a ⊕⊕ Texp e2a)  Texp (scrut ? e1 : e2)a"
      by (rule Texp_IfThenElse)
    hence "substitute (FBinds Γae) (thunks Γ) (Texp scrut0 ⊗⊗ (Texp e1a ⊕⊕ Texp e2a) ⊗⊗ Fstack as S)  substitute (FBinds Γae) (thunks Γ) (Texp (scrut ? e1 : e2)a ⊗⊗ Fstack as S)"
      by (rule substitute_mono2'[OF both_mono1'])
    thus "prognosis ae (a#as) 0 (Γ, scrut, Alts e1 e2 # S)  prognosis ae as a (Γ, scrut ? e1 : e2, S)"
      by (simp, intro pathsCard_mono' paths_mono)
  next
    fix ae as a Γ b e1 e2 S
    have "Texp (if b then e1 else e2)a  Texp e1a ⊕⊕ Texp e2a"
      by (auto simp add: either_above_arg1 either_above_arg2)
    hence "substitute (FBinds Γae) (thunks Γ) (Texp (if b then e1 else e2)a ⊗⊗ Fstack as S)  substitute (FBinds Γae) (thunks Γ) (Texp (Bool b)0 ⊗⊗ (Texp e1a ⊕⊕ Texp e2a) ⊗⊗ Fstack as S)"
      by (rule substitute_mono2'[OF both_mono1'[OF below_trans[OF _ both_above_arg2]]])
    thus "prognosis ae as a (Γ, if b then e1 else e2, S)  prognosis ae (a#as) 0 (Γ, Bool b, Alts e1 e2 # S)"
      by (auto intro!: pathsCard_mono' paths_mono)
  qed

end

context TTreeAnalysisCardinalityHeap
begin

  definition cHeap where
    "cHeap Γ e = (Λ a. pathsCard (paths (Theap Γ ea)))"

  lemma cHeap_simp: "(cHeap Γ e)a = pathsCard (paths (Theap Γ ea))"
    unfolding cHeap_def  by (rule beta_cfun) (intro cont2cont)
  
  sublocale CardinalityHeap cHeap.
 
  sublocale CardinalityHeapSafe cHeap Aheap
  proof
    fix x Γ e a
    assume "x  thunks Γ"
    moreover
    assume "many  (cHeap Γ ea) x"
    hence "many  pathsCard (paths (Theap Γ e a)) x" unfolding cHeap_def by simp
    hence "p (paths (Theap Γ ea)). ¬ (one_call_in_path x p)" unfolding pathsCard_def
      by (auto split: if_splits)
    ultimately
    show "(Aheap Γ ea) x = up0"
      by (metis Theap_thunk)
  next
    fix Γ e a
    show "edom (cHeap Γ ea) = edom (Aheap Γ ea)"
    by (simp add: cHeap_def Union_paths_carrier carrier_Fheap)
  qed

  sublocale CardinalityPrognosisEdom prognosis 
  proof
    fix ae as a Γ e S
    show "edom (prognosis ae as a (Γ, e, S))  fv Γ  fv e  fv S"
      apply (simp add: Union_paths_carrier)
      apply (rule carrier_substitute_below)
      apply (auto simp add: carrier_Fexp dest: subsetD[OF Aexp_edom] subsetD[OF carrier_Fstack] subsetD[OF ap_fv_subset] subsetD[OF carrier_FBinds])
      done
  qed
  
  sublocale CardinalityPrognosisLet prognosis cHeap
  proof
    fix Δ Γ :: heap and e :: exp and S :: stack and  ae :: AEnv and a :: Arity and as
    assume "atom ` domA Δ ♯* Γ"
    assume "atom ` domA Δ ♯* S"
    assume "edom ae  domA Γ  upds S"

    have "domA Δ  edom ae = {}"
      using fresh_distinct[OF atom ` domA Δ ♯* Γ] fresh_distinct_fv[OF atom ` domA Δ ♯* S] 
            edom ae  domA Γ  upds S ups_fv_subset[of S]
      by auto

    have const_on1:  " x. const_on (FBinds Δ(Aheap Δ ea)) (carrier ((FBinds Γae) x)) empty"
      unfolding const_on_edom_disj using fresh_distinct_fv[OF atom ` domA Δ ♯* Γ]
      by (auto dest!: subsetD[OF carrier_FBinds] subsetD[OF Texp.edom_AnalBinds])
    have const_on2:  "const_on (FBinds Δ(Aheap Δ ea)) (carrier (Fstack as S)) empty"
      unfolding const_on_edom_disj using fresh_distinct_fv[OF atom ` domA Δ ♯* S]
      by (auto dest!: subsetD[OF carrier_FBinds] subsetD[OF carrier_Fstack] subsetD[OF Texp.edom_AnalBinds] subsetD[OF ap_fv_subset ])
    have  const_on3: "const_on (FBinds Γae) (- (- domA Δ)) TTree.empty"
      and const_on4: "const_on (FBinds Δ(Aheap Δ ea)) (domA Γ) TTree.empty"
      unfolding const_on_edom_disj using fresh_distinct[OF atom ` domA Δ ♯* Γ]
      by (auto dest!:  subsetD[OF Texp.edom_AnalBinds])

    have disj1: " x. carrier ((FBinds Γae) x)  domA Δ = {}"
      using fresh_distinct_fv[OF atom ` domA Δ ♯* Γ]
      by (auto dest: subsetD[OF carrier_FBinds])
    hence disj1': " x. carrier ((FBinds Γae) x)  - domA Δ" by auto
    have disj2: " x. carrier (Fstack as S)  domA Δ = {}"
      using fresh_distinct_fv[OF atom ` domA Δ ♯* S] by (auto dest!: subsetD[OF carrier_Fstack])
    hence disj2': "carrier (Fstack as S)  - domA Δ" by auto
    

    {
    fix x
    have "(FBinds (Δ @ Γ)(ae  Aheap Δ ea)) x = (FBinds Γae) x ⊗⊗ (FBinds Δ(Aheap Δ ea)) x"
    proof (cases "x  domA Δ")
      case True
      have "map_of Γ x = None" using True fresh_distinct[OF atom ` domA Δ ♯* Γ] by (metis disjoint_iff_not_equal domA_def map_of_eq_None_iff)
      moreover
      have "ae x = " using True domA Δ  edom ae = {} by auto
      ultimately
      show ?thesis using True 
          by (auto simp add: Texp.AnalBinds_lookup empty_is_bottom[symmetric] cong: option.case_cong)
    next
      case False
      have "map_of Δ x = None" using False by (metis domA_def map_of_eq_None_iff)
      moreover
      have "(Aheap Δ ea) x = " using False using edom_Aheap by (metis contra_subsetD edomIff)
      ultimately
      show ?thesis using False
         by (auto simp add: Texp.AnalBinds_lookup empty_is_bottom[symmetric] cong: option.case_cong)
    qed
    }
    note FBinds = ext[OF this]
    
    {
    have "pathsCard (paths (substitute (FBinds (Δ @ Γ)(Aheap Δ ea  ae)) (thunks (Δ @ Γ)) (Texp ea ⊗⊗ Fstack as S)))
      = pathsCard (paths (substitute (FBinds Γae) (thunks (Δ @ Γ)) (substitute (FBinds Δ(Aheap Δ ea))  (thunks (Δ @ Γ))  (Texp ea ⊗⊗ Fstack as S))))"
       by (simp add: substitute_substitute[OF const_on1] FBinds)
    also have "substitute (FBinds Γae) (thunks (Δ @ Γ)) = substitute (FBinds Γae) (thunks Γ)"
      apply (rule substitute_cong_T)
      using const_on3
      by (auto dest: subsetD[OF thunks_domA])
    also have "substitute (FBinds Δ(Aheap Δ ea)) (thunks (Δ @ Γ)) = substitute (FBinds Δ(Aheap Δ ea)) (thunks Δ)"
      apply (rule substitute_cong_T)
      using const_on4
      by (auto dest: subsetD[OF thunks_domA])
    also have "substitute (FBinds Δ(Aheap Δ ea)) (thunks Δ) (Texp ea ⊗⊗ Fstack as S) = substitute (FBinds Δ(Aheap Δ ea)) (thunks Δ) (Texp ea) ⊗⊗ Fstack as S"
      by (rule substitute_only_empty_both[OF const_on2])
    also note calculation
    }
    note eq_imp_below[OF this]
    also
    note env_restr_split[where S = "domA Δ"]
    also
    have "pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (substitute (FBinds Δ(Aheap Δ ea)) (thunks Δ) (Texp ea) ⊗⊗ Fstack as S))) f|` domA Δ 
        = pathsCard (paths (ttree_restr (domA Δ) (substitute (FBinds Δ(Aheap Δ ea)) (thunks Δ) (Texp ea))))"
          by (simp add: filter_paths_conv_free_restr ttree_restr_both ttree_rest_substitute[OF disj1]  ttree_restr_is_empty[OF disj2])
    also
    have "ttree_restr (domA Δ) (substitute (FBinds Δ(Aheap Δ ea)) (thunks Δ) (Texp ea))  Theap Δ ea"  by (rule Theap_substitute)
    also
    have "pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (substitute (FBinds Δ(Aheap Δ ea)) (thunks Δ) (Texp ea) ⊗⊗ Fstack as S))) f|` (- domA Δ) =
          pathsCard (paths (substitute (FBinds Γae) (thunks Γ) (ttree_restr (- domA Δ) (substitute (FBinds Δ(Aheap Δ ea)) (thunks Δ) (Texp ea)) ⊗⊗ Fstack as S)))"
          by (simp add: filter_paths_conv_free_restr2 ttree_rest_substitute2[OF disj1' const_on3] ttree_restr_both  ttree_restr_noop[OF disj2'])
    also have "ttree_restr (- domA Δ) (substitute (FBinds Δ(Aheap Δ ea))  (thunks Δ)  (Texp ea))  Texp (Terms.Let Δ e)a" by (rule Texp_Let)
    finally
    show "prognosis (Aheap Δ ea  ae) as a (Δ @ Γ, e, S)  cHeap Δ ea  prognosis ae as a (Γ, Terms.Let Δ e, S)"
      by (simp add: cHeap_def del: fun_meet_simp) 
  qed

  sublocale CardinalityPrognosisSafe prognosis cHeap Aheap Aexp ..
end


end