Theory Cardinality-Domain-Lists

theory "Cardinality-Domain-Lists"
imports Launchbury.Vars "Launchbury.Nominal-HOLCF" Launchbury.Env "Cardinality-Domain" "Set-Cpo" "Env-Set-Cpo"
begin

fun no_call_in_path where
  "no_call_in_path x []  True"
 | "no_call_in_path x (y#xs)  y  x  no_call_in_path x xs"

fun one_call_in_path where
  "one_call_in_path x []  True"
 | "one_call_in_path x (y#xs)  (if x = y then no_call_in_path x xs else one_call_in_path x xs)"

lemma no_call_in_path_set_conv:
  "no_call_in_path x p  x  set p"
  by(induction p) auto 

lemma one_call_in_path_filter_conv:
  "one_call_in_path x p  length (filter (λ x'. x' = x) p)  1"
  by(induction p) (auto simp add: no_call_in_path_set_conv filter_empty_conv)

lemma no_call_in_tail: "no_call_in_path x (tl p)  (no_call_in_path x p  one_call_in_path x p  hd p = x)"
  by(induction p) auto

lemma no_imp_one: "no_call_in_path x p  one_call_in_path x p"
  by (induction p) auto

lemma one_imp_one_tail: "one_call_in_path x p  one_call_in_path x (tl p)"
  by (induction p) (auto split: if_splits intro: no_imp_one)

lemma more_than_one_setD:
  "¬ one_call_in_path x p  x  set p" 
  by (induction p) (auto split: if_splits)

lemma no_call_in_path[eqvt]: "no_call_in_path p x  no_call_in_path (π  p) (π  x)"
  by (induction p x rule: no_call_in_path.induct) auto

lemma one_call_in_path[eqvt]: "one_call_in_path p x  one_call_in_path (π  p) (π  x)"
  by (induction p x rule: one_call_in_path.induct) (auto dest: no_call_in_path)

definition pathCard :: "var list   (var  two)"
  where "pathCard p x = (if no_call_in_path x p then none else (if one_call_in_path x p then once else many))"

lemma pathCard_Nil[simp]: "pathCard [] = "
   by rule (simp add: pathCard_def)

lemma pathCard_Cons[simp]: "pathCard (x#xs) x = two_addonce(pathCard xs x)"
  unfolding pathCard_def
  by (auto simp add: two_add_simp)

lemma pathCard_Cons_other[simp]: "x'  x  pathCard (x#xs) x' = pathCard xs x'"
  unfolding pathCard_def by auto

lemma no_call_in_path_filter[simp]: "no_call_in_path x [xxs . x  S]  no_call_in_path x xs  x  S"
  by (induction xs) auto

lemma one_call_in_path_filter[simp]: "one_call_in_path x [xxs . x  S]  one_call_in_path x xs  x  S"
  by (induction xs) auto

definition pathsCard :: "var list set  (var  two)"
  where "pathsCard ps x = (if ( p  ps. no_call_in_path x p) then none else (if ( pps. one_call_in_path x p) then once else many))"

lemma paths_Card_above:
  "p  ps  pathCard p  pathsCard ps"
  by (rule fun_belowI) (auto simp add: pathsCard_def pathCard_def)

lemma pathsCard_below:
  assumes  " p. p  ps  pathCard p  ce"
  shows "pathsCard ps  ce"
proof(rule fun_belowI)
  fix x
  show "pathsCard ps x  ce x"
    by (auto simp add: pathsCard_def pathCard_def split: if_splits dest!: fun_belowD[OF assms, where x = x] elim: below_trans[rotated] dest: no_imp_one)
qed

lemma pathsCard_mono:
  "ps  ps'  pathsCard ps  pathsCard ps'"
  by (auto intro: pathsCard_below paths_Card_above)

lemmas pathsCard_mono' = pathsCard_mono[folded below_set_def]

lemma record_call_pathsCard: 
  "pathsCard ({ tl p | p . p  fs  hd p = x})  record_call x(pathsCard fs)"
proof (rule pathsCard_below)
  fix p'
  assume "p'  {tl p |p. p  fs  hd p = x}"
  then obtain p where "p' = tl p" and "p  fs" and "hd p = x" by auto
  
  have "pathCard (tl p)  record_call x(pathCard p)"
    apply (rule fun_belowI)
    using hd p = x by (auto simp add: pathCard_def record_call_simp no_call_in_tail dest: one_imp_one_tail)
    
  hence "pathCard (tl p)  record_call x(pathsCard fs)"
    by (rule below_trans[OF _ monofun_cfun_arg[OF  paths_Card_above[OF p  fs]]])
  thus "pathCard p'  record_call x(pathsCard fs)" using p' = _ by simp
qed
  
lemma pathCards_noneD:
  "pathsCard ps x = none  x  (set ` ps)"
  by (auto simp add: pathsCard_def no_call_in_path_set_conv split:if_splits)

lemma cont_pathsCard[THEN cont_compose, cont2cont, simp]:
  "cont pathsCard"
  by(fastforce intro!: cont2cont_lambda cont_if_else_above simp add: pathsCard_def below_set_def)

lemma pathsCard_eqvt[eqvt]: "π  pathsCard ps x = pathsCard (π  ps) (π  x)"
  unfolding pathsCard_def by perm_simp rule

lemma edom_pathsCard[simp]: "edom (pathsCard ps) = (set ` ps)"
  unfolding edom_def pathsCard_def
  by (auto simp add:  no_call_in_path_set_conv)

lemma env_restr_pathsCard[simp]: "pathsCard ps f|` S = pathsCard (filter (λ x. x  S) ` ps)"
  by (auto simp add: pathsCard_def lookup_env_restr_eq)


end