Theory Aux

Up to index of Isabelle/HOL/JinjaThreads

theory Aux
imports FinFun Transitive_Closure_Table Code_Char

(*  Title:      JinjaThreads/Common/Aux.thy
    Author:     Andreas Lochbihler, David von Oheimb, Tobias Nipkow

    Based on the Jinja theory Common/Aux.thy by David von Oheimb and Tobias Nipkow
*)

header {* 
  \isaheader{Auxiliary Definitions and Lemmata}
*}

theory Aux 
imports
  Main
  "../../FinFun/FinFun"
  "Transitive_Closure_Table"
  Code_Char
begin


(* FIXME move and possibly turn into a general simproc *)
lemma nat_add_max_le[simp]:
  "((n::nat) + max i j ≤ m) = (n + i ≤ m ∧ n + j ≤ m)"
 (*<*)by arith(*>*)

lemma Suc_add_max_le[simp]:
  "(Suc(n + max i j) ≤ m) = (Suc(n + i) ≤ m ∧ Suc(n + j) ≤ m)"
(*<*)by arith(*>*)

notation Some ("(⌊_⌋)")

(*<*)
declare
 option.splits[split]
 Let_def[simp]
 subset_insertI2 [simp]
(*>*)


subsection {*@{text distinct_fst}*}
 
definition
  distinct_fst  :: "('a × 'b) list => bool"
where
  "distinct_fst  ≡  distinct o map fst"

lemma distinct_fst_Nil [simp]:
  "distinct_fst []"
 (*<*)
apply (unfold distinct_fst_def)
apply (simp (no_asm))
done
(*>*)

lemma distinct_fst_Cons [simp]:
  "distinct_fst ((k,x)#kxs) = (distinct_fst kxs ∧ (∀y. (k,y) ∉ set kxs))"
(*<*)
apply (unfold distinct_fst_def)
apply (auto simp:image_def)
done
(*>*)

lemma distinct_fstD: "[| distinct_fst xs; (x, y) ∈ set xs; (x, z) ∈ set xs |] ==> y = z"
by(induct xs) auto

lemma map_of_SomeI:
  "[| distinct_fst kxs; (k,x) ∈ set kxs |] ==> map_of kxs k = Some x"
(*<*)by (induct kxs) (auto simp:fun_upd_apply)(*>*)


subsection {* Using @{term list_all2} for relations *}

definition
  fun_of :: "('a × 'b) set => 'a => 'b => bool"
where
  "fun_of S ≡ λx y. (x,y) ∈ S"

text {* Convenience lemmas *}
(*<*)
declare fun_of_def [simp]
(*>*)
lemma rel_list_all2_Cons [iff]:
  "list_all2 (fun_of S) (x#xs) (y#ys) = 
   ((x,y) ∈ S ∧ list_all2 (fun_of S) xs ys)"
  (*<*)by simp(*>*)

lemma rel_list_all2_Cons1:
  "list_all2 (fun_of S) (x#xs) ys = 
  (∃z zs. ys = z#zs ∧ (x,z) ∈ S ∧ list_all2 (fun_of S) xs zs)"
  (*<*)by (cases ys) auto(*>*)

lemma rel_list_all2_Cons2:
  "list_all2 (fun_of S) xs (y#ys) = 
  (∃z zs. xs = z#zs ∧ (z,y) ∈ S ∧ list_all2 (fun_of S) zs ys)"
  (*<*)by (cases xs) auto(*>*)

lemma rel_list_all2_refl:
  "(!!x. (x,x) ∈ S) ==> list_all2 (fun_of S) xs xs"
  (*<*)by (simp add: list_all2_refl)(*>*)

lemma rel_list_all2_antisym:
  "[| (!!x y. [|(x,y) ∈ S; (y,x) ∈ T|] ==> x = y); 
     list_all2 (fun_of S) xs ys; list_all2 (fun_of T) ys xs |] ==> xs = ys"
  (*<*)by (rule list_all2_antisym) auto(*>*)

lemma rel_list_all2_trans: 
  "[| !!a b c. [|(a,b) ∈ R; (b,c) ∈ S|] ==> (a,c) ∈ T;
    list_all2 (fun_of R) as bs; list_all2 (fun_of S) bs cs|] 
  ==> list_all2 (fun_of T) as cs"
  (*<*)by (rule list_all2_trans) auto(*>*)

lemma rel_list_all2_update_cong:
  "[| i<size xs; list_all2 (fun_of S) xs ys; (x,y) ∈ S |] 
  ==> list_all2 (fun_of S) (xs[i:=x]) (ys[i:=y])"
  (*<*)by (simp add: list_all2_update_cong)(*>*)

lemma rel_list_all2_nthD:
  "[| list_all2 (fun_of S) xs ys; p < size xs |] ==> (xs!p,ys!p) ∈ S"
  (*<*)by (drule list_all2_nthD) auto(*>*)

lemma rel_list_all2I:
  "[| length a = length b; !!n. n < length a ==> (a!n,b!n) ∈ S |] ==> list_all2 (fun_of S) a b"
  (*<*)by (erule list_all2_all_nthI) simp(*>*)

(*<*)declare fun_of_def [simp del](*>*)


fun flatten :: "'a list list => 'a list" ("\<down>_\<down>" [50] 80)
where
  "flatten [] = []"
| "flatten (xs # xss) = xs @ flatten xss"

lemma set_flatten_Union_set [simp]:
  "set (flatten xs) = Union (set (map set xs))"
by(induct xs, auto)

lemma flatten_append [simp]: "flatten (xs @ ys) = flatten xs @ flatten ys"
by(induct xs, auto)


lemma f_nth_set:
  "[| f (xs ! n) = v; n < length xs |] ==> v ∈ f ` set xs"
apply(induct xs arbitrary: n)
 apply(simp)
apply(case_tac "n")
apply(auto)
done


lemma map_eq_imp_length_eq': 
  "map f xs = map g ys ==> length xs = length ys"
apply(induct xs arbitrary: ys)
 apply(simp)
apply(auto simp add: Cons_eq_map_conv)
done


lemma replicate_eq_append_conv: 
  "(replicate n x = xs @ ys) = (∃m≤n. xs = replicate m x ∧ ys = replicate (n-m) x)"
proof(induct n arbitrary: xs ys)
  case 0 thus ?case by simp
next
  case (Suc n xs ys)
  have IH: "!!xs ys. (replicate n x = xs @ ys) = (∃m≤n. xs = replicate m x ∧ ys = replicate (n - m) x)" by fact
  show ?case
  proof(unfold replicate_Suc, rule iffI)
    assume a: "x # replicate n x = xs @ ys"
    show "∃m≤Suc n. xs = replicate m x ∧ ys = replicate (Suc n - m) x"
    proof(cases xs)
      case Nil
      thus ?thesis using a
        by(auto)
    next
      case (Cons X XS)
      with a have x: "x = X" and "replicate n x = XS @ ys" by auto
      hence "∃m≤n. XS = replicate m x ∧ ys = replicate (n - m) x"
        by -(rule IH[THEN iffD1])
      then obtain m where "m ≤ n" and XS: "XS = replicate m x" and ys: "ys = replicate (n - m) x" by blast
      with x Cons show ?thesis
        by(fastsimp)
    qed
  next
    assume "∃m≤Suc n. xs = replicate m x ∧ ys = replicate (Suc n - m) x"
    then obtain m where m: "m ≤ Suc n" and xs: "xs = replicate m x" and ys: "ys = replicate (Suc n - m) x" by blast
    thus "x # replicate n x = xs @ ys"
      by(simp add: replicate_add[THEN sym])
  qed
qed

lemma map_eq_append_conv:
  "map f xs = ys @ zs <-> (∃ys' zs'. map f ys' = ys ∧ map f zs' = zs ∧ xs = ys' @ zs')"
apply(rule iffI)
 apply(metis append_eq_conv_conj append_take_drop_id assms drop_map take_map)
by(clarsimp)

lemma append_eq_map_conv:
  "ys @ zs = map f xs <-> (∃ys' zs'. map f ys' = ys ∧ map f zs' = zs ∧ xs = ys' @ zs')"
unfolding map_eq_append_conv[symmetric]
by auto

lemma map_eq_map_conv:
  "map f xs = map g ys <-> list_all2 (λx y. f x = g y) xs ys"
apply(induct xs arbitrary: ys)
apply(auto simp add: list_all2_Cons1 Cons_eq_map_conv)
done

lemma map_upd_map_add: "X(V \<mapsto> v) = (X ++ [V \<mapsto> v])"
by(simp)

lemma Collect_eq_singleton_conv:
  "{a. P a} = {a} <-> P a ∧ (∀a'. P a' --> a = a')"
by(auto)

lemmas filter_replicate_conv = filter_replicate

lemma if_else_if_else_eq_if_else [simp]:
  "(if b then x else if b then y else z) = (if b then x else z)"
by(simp)

lemma disjE3: "[| P ∨ Q ∨ R; P ==> S; Q ==> S; R ==> S |] ==> S"
by auto

lemma length_greater_Suc_0_conv: "Suc 0 < length xs <-> (∃x x' xs'. xs = x # x' # xs')"
by(cases xs, auto simp add: neq_Nil_conv)

lemmas zip_same_conv = zip_same_conv_map

lemma map_eq_all_nth_conv:
  "map f xs = ys <-> length xs = length ys ∧ (∀n < length xs. f (xs ! n) = ys ! n)"
apply(induct xs arbitrary: ys)
apply(fastsimp simp add: nth_Cons Suc_length_conv split: nat.splits)+
done

lemma nth_Cons_subtract: "0 < n ==> (x # xs) ! n = xs ! (n - 1)"
by(auto simp add: nth_Cons split: nat.split)

lemma prod_rec_split [simp]: "prod_rec = split"
by(simp add: expand_fun_eq)

lemma rtranclp_False [simp]: "(λa b. False)** = op ="
by(auto simp add: expand_fun_eq elim: rtranclp_induct)

lemmas rtranclp_induct3 =
  rtranclp_induct[where a="(ax, ay, az)" and b="(bx, by, bz)", split_rule, consumes 1, case_names refl step]

lemmas tranclp_induct3 =
  tranclp_induct[where a="(ax, ay, az)" and b="(bx, by, bz)", split_rule, consumes 1, case_names refl step]

lemmas rtranclp_induct4 =
  rtranclp_induct[where a="(ax, ay, az, aw)" and b="(bx, by, bz, bw)", split_rule, consumes 1, case_names refl step]

lemmas tranclp_induct4 =
  tranclp_induct[where a="(ax, ay, az, aw)" and b="(bx, by, bz, bw)", split_rule, consumes 1, case_names refl step]

lemma converse_tranclpE:
  assumes "tranclp r x z"
  obtains (base) "r x z"
        | (step) y where "r x y" "tranclp r y z"
using tranclpD[OF assms]
by(blast elim: converse_rtranclpE dest: rtranclp_into_tranclp2)

lemmas converse_tranclp_induct2 =
  converse_tranclp_induct [of _ "(ax,ay)" "(bx,by)", split_rule,
                 consumes 1, case_names base step]

lemma wfP_induct' [consumes 1, case_names wfP]:
  "[|wfP r; !!x. (!!y. r y x ==> P y) ==> P x|] ==> P a"
by(blast intro: wfP_induct)

lemma wfP_induct2 [consumes 1, case_names wfP]:
  "[|wfP r; !!x x'. (!!y y'. r (y, y') (x, x') ==> P y y') ==> P x x' |] ==> P x x'"
by(drule wfP_induct'[where P="λ(x, y). P x y"]) blast+

lemma wfP_minimalE:
  assumes "wfP r"
  and "P x"
  obtains z where "P z" "r^** z x" "!!y. r y z ==> ¬ P y"
proof -
  let ?Q = "λx'. P x' ∧ r^** x' x"
  from `P x` have "?Q x" by blast
  from `wfP r` have "!!Q. x ∈ Q --> (∃z∈Q. ∀y. r y z --> y ∉ Q)"
    unfolding wfP_eq_minimal by blast
  from this[rule_format, of ?Q] `?Q x`
  obtain z where "?Q z" and min: "!!y. r y z ==> ¬ ?Q y" by(auto simp add: mem_def)
  from `?Q z` have "P z" "r^** z x" by auto
  moreover
  { fix y
    assume "r y z"
    hence "¬ ?Q y" by(rule min)
    moreover from `r y z` `r^** z x` have "r^** y x"
      by(rule converse_rtranclp_into_rtranclp)
    ultimately have "¬ P y" by blast }
  ultimately show thesis ..
qed

subsection {* reflexive transitive closure for label relations *}

inductive converse3p :: "('a => 'b => 'c => bool) => 'c => 'b => 'a => bool"
  for r :: "'a => 'b => 'c => bool"
where
  converse3pI: "r a b c ==> converse3p r c b a"

lemma converse3p_converse3p: "converse3p (converse3p r) = r"
by(auto intro: converse3pI intro!: ext elim: converse3p.cases)

lemma converse3pD: "converse3p r c b a ==> r a b c"
by(auto elim: converse3p.cases)

inductive rtrancl3p :: "('a => 'b => 'a => bool) => 'a => 'b list => 'a => bool"
  for r :: "'a => 'b => 'a => bool"
  where 
  rtrancl3p_refl [intro!, simp]: "rtrancl3p r a [] a"
| rtrancl3p_step: "[| rtrancl3p r a bs a'; r a' b a'' |] ==> rtrancl3p r a (bs @ [b]) a''"

lemmas rtrancl3p_induct3 =
  rtrancl3p.induct[of _ "(ax,ay,az)" _ "(cx,cy,cz)", split_format (complete),
                 consumes 1, case_names refl step]

lemmas rtrancl3p_induct4 = 
  rtrancl3p.induct[of _ "(ax,ay,az,aw)" _ "(cx,cy,cz,cw)", split_format (complete),
                 consumes 1, case_names refl step]

lemma rtrancl3p_induct4' [consumes 1, case_names refl step]:
  assumes major: "rtrancl3p r (ax, (ay, az), aw) bs (cx, (cy, cz), cw)"
  and refl: "!!a aa b ba. P a aa b ba [] a aa b ba"
  and step: "!!a aa b ba bs ab ac bb bc bd ad ae be bf.
       [| rtrancl3p r (a, (aa, b), ba) bs (ab, (ac, bb), bc);
         P a aa b ba bs ab ac bb bc; r (ab, (ac, bb), bc) bd (ad, (ae, be), bf) |]
       ==> P a aa b ba (bs @ [bd]) ad ae be bf"
  shows "P ax ay az aw bs cx cy cz cw"
using major
apply -
apply(drule_tac P="λ(a, (aa, b), ba) bs (cx, (cy, cz), cw). P a aa b ba bs cx cy cz cw" in rtrancl3p.induct)
by(auto intro: refl step)

lemma rtrancl3p_induct1:
  "[| rtrancl3p r a bs c; P a; !!bs c b d. [| rtrancl3p r a bs c; r c b d; P c |] ==> P d |] ==> P c"
apply(induct rule: rtrancl3p.induct)
apply(auto)
done

lemma rtrancl3p_trans [trans]:
  assumes one: "rtrancl3p r a bs a'"
  and two: "rtrancl3p r a' bs' a''"
  shows "rtrancl3p r a (bs @ bs') a''"
using two one
proof(induct rule: rtrancl3p.induct)
  case rtrancl3p_refl thus ?case by simp
next
  case rtrancl3p_step thus ?case
    by(auto simp only: append_assoc[symmetric] intro: rtrancl3p.rtrancl3p_step)
qed

lemma rtrancl3p_step_converse:
  assumes step: "r a b a'"
  and stepify: "rtrancl3p r a' bs a''"
  shows "rtrancl3p r a (b # bs) a''"
using stepify step
proof(induct rule: rtrancl3p.induct)
  case rtrancl3p_refl 
  with rtrancl3p.rtrancl3p_refl[where r=r and a=a] show ?case 
    by(auto dest: rtrancl3p.rtrancl3p_step simp del: rtrancl3p.rtrancl3p_refl)
next
  case rtrancl3p_step thus ?case
    unfolding append_Cons[symmetric]
    by -(rule rtrancl3p.rtrancl3p_step)
qed

lemma converse_rtrancl3p_step:
  "rtrancl3p r a (b # bs) a'' ==> ∃a'. r a b a' ∧ rtrancl3p r a' bs a''"
apply(induct bs arbitrary: a'' rule: rev_induct)
 apply(erule rtrancl3p.cases)
  apply(clarsimp)+
 apply(erule rtrancl3p.cases)
  apply(clarsimp)
  apply(rule_tac x="a''a" in exI)
  apply(clarsimp)
 apply(clarsimp)
apply(erule rtrancl3p.cases)
 apply(clarsimp)
apply(clarsimp)
by(fastsimp intro: rtrancl3p_step)

lemma converse_rtrancl3pD:
  "rtrancl3p (converse3p r) a' bs a ==> rtrancl3p r a (rev bs) a'"
apply(induct rule: rtrancl3p.induct)
 apply(fastsimp intro: rtrancl3p.intros)
apply(auto dest: converse3pD intro: rtrancl3p_step_converse)
done

lemma rtrancl3p_converseD:
  "rtrancl3p r a bs a' ==> rtrancl3p (converse3p r) a' (rev bs) a"
proof(induct rule: rtrancl3p.induct)
  case rtrancl3p_refl thus ?case
    by(auto intro: rtrancl3p.intros)
next
  case rtrancl3p_step thus ?case
    by(auto intro: rtrancl3p_step_converse converse3p.intros)
qed

lemma rtrancl3p_converse_induct [consumes 1, case_names refl step]:
  assumes ih: "rtrancl3p r a bs a''"
  and refl: "!!a. P a [] a"
  and step: "!!a b a' bs a''. [| rtrancl3p r a' bs a''; r a b a'; P a' bs a'' |] ==> P a (b # bs) a''"
  shows "P a bs a''"
  using ih
proof(induct bs arbitrary: a a'')
  case Nil thus ?case
    by(auto elim: rtrancl3p.cases intro: refl)
next
  case Cons thus ?case
    by(auto dest!: converse_rtrancl3p_step intro: step)
qed  

lemma rtrancl3p_converse_induct' [consumes 1, case_names refl step]:
  assumes ih: "rtrancl3p r a bs a''"
  and refl: "P a'' []"
  and step: "!!a b a' bs. [| rtrancl3p r a' bs a''; r a b a'; P a' bs |] ==> P a (b # bs)"
  shows "P a bs"
using rtrancl3p_converse_induct[OF ih, where P="λa bs a'. a' = a'' --> P a bs"]
by(auto intro: refl step)

lemma rtrancl3p_converseE[consumes 1, case_names refl step]:
  "[| rtrancl3p r a bs a'';
     [| a = a''; bs = [] |] ==> thesis;
     !!bs' b a'. [| bs = b # bs'; r a b a'; rtrancl3p r a' bs' a'' |] ==> thesis |]
  ==> thesis"
by(induct rule: rtrancl3p_converse_induct)(auto)


lemma rtrancl3p_induct' [consumes 1, case_names refl step]:
  assumes major: "rtrancl3p r a bs c"
  and refl: "P a [] a"
  and step: "!!bs a' b a''. [| rtrancl3p r a bs a'; P a bs a'; r a' b a'' |]
             ==> P a (bs @ [b]) a''"
  shows "P a bs c"
proof -
  from major have "(P a [] a ∧ (∀bs a' b a''. rtrancl3p r a bs a' ∧ P a bs a' ∧ r a' b a'' --> P a (bs @ [b]) a'')) --> P a bs c"
    by-(erule rtrancl3p.induct, blast+)
  with refl step show ?thesis by blast
qed



lemma list_all2_induct[consumes 1, case_names Nil Cons]:
  assumes major: "list_all2 P xs ys"
  and Nil: "Q [] []"
  and Cons: "!!x xs y ys. [| P x y; Q xs ys |] ==> Q (x # xs) (y # ys)"
  shows "Q xs ys"
using major
by(induct xs arbitrary: ys)(auto simp add: list_all2_Cons1 Nil intro!: Cons)

lemma list_all2_split:
  assumes major: "list_all2 P xs ys"
  and split: "!!x y. P x y ==> ∃z. Q x z ∧ R z y"
  shows "∃zs. list_all2 Q xs zs ∧ list_all2 R zs ys"
using major
by(induct rule: list_all2_induct)(auto dest: split)

subsection {* Concatenation for @{typ String.literal} *}

definition concat :: "String.literal list => String.literal"
where [code del]: "concat xs = implode (List.concat (map explode xs))"

code_const concat
  (SML "String.concat")
  (Haskell "concat")
  (OCaml "String.concat \"\"")

hide (open) const concat

lemma map_le_SomeD: "[| m ⊆m m'; m x = ⌊y⌋ |] ==> m' x = ⌊y⌋"
by(auto simp add: map_le_def dest: bspec)

lemma take_eq_take_le_eq:
  "[| take n xs = take n ys; m ≤ n |] ==> take m xs = take m ys"
by(metis min_max.le_iff_inf take_take)

lemma take_list_update_beyond:
  "n ≤ m ==> take n (xs[m := x]) = take n xs"
by(cases "n ≤ length xs")(rule nth_take_lemma, simp_all)

lemma nat_fun_sum_eq_conv:
  fixes f :: "'a => nat"
  shows "(λa. f a + g a) = (λa. 0) <-> f = (λa .0) ∧ g = (λa. 0)"
by(auto simp add: expand_fun_eq)

end