Theory TA_Impl_Misc2

theory TA_Impl_Misc2
  imports
    Munta_Base.TA_Impl_Misc
    "HOL-Library.Sublist"
    "List-Index.List_Index"
    Automatic_Refinement.Misc
begin

lemma mem_nth:
  "x  set xs   i < length xs. xs ! i = x"
  by (metis index_less_size_conv nth_index)

lemma union_subsetI:
  "A  B  C  D" if "A  C" "B  D"
  using that by blast

lemma map_eq_imageD:
  "f ` set xs = set ys" if "map f xs = ys"
  using that by auto

lemma if_contract:
  "(if a then x else if b then x else y) = (if a  b then x else y)" for a x b y
  by (rule SMT.z3_rule)

paragraph ‹More intros›

named_theorems more_intros
named_theorems more_elims
lemmas [more_intros] =
  image_eqI[rotated] CollectI subsetI

lemmas [more_elims] =
  CollectE

paragraph ‹Finiteness›

lemma finite_prodI:
  "finite {(a,b). P a  Q b}" if "finite {a. P a}" "finite {a. Q a}"
  using that by simp

lemma finite_prodI3:
  "finite {(a,b,c). P a  Q b  Q1 c}"
  if "finite {a. P a}" "finite {a. Q a}" "finite {a. Q1 a}"
  using that by simp

lemma finite_prodI4:
  "finite {(a,b,c,d). P a  Q b  Q1 c  Q2 d}"
  if "finite {a. P a}" "finite {a. Q a}" "finite {a. Q1 a}" "finite {a. Q2 a}"
  using that by simp

lemma finite_prodI5:
  "finite {(a,b,c,d,e). P a  Q b  Q1 c  Q2 d  Q3 e}"
  if "finite {a. P a}" "finite {a. Q a}" "finite {a. Q1 a}" "finite {a. Q2 a}" "finite {a. Q3 a}"
  using that by simp

named_theorems finite_intros
named_theorems more_finite_intros

lemmas [finite_intros] =
  finite_UnI finite_Union finite_imageI
  finite_lists_length_eq finite_lists_length_le
  finite_subset_distinct distinct_finite_set

lemmas [more_finite_intros] =
  finite_prodI finite_prodI3 finite_prodI4 finite_prodI5

paragraph ‹Lists›

lemma fold_evD2:
  assumes
    "P y (fold f xs acc)" "¬ P y acc"
    " acc x. ¬ P y acc  Q acc  P y (f x acc)  x  set xs  x = y"
    "Q acc" " acc x. Q acc  Q (f x acc)"
    " acc x. ¬ P y acc  Q acc  P y (f x acc)  R y"
  shows " ys zs. xs = ys @ y # zs  ¬ P y (fold f ys acc)  P y (f y (fold f ys acc))  R y"
proof -
  from fold_evD'[OF assms(2,1)] obtain x ys zs where *:
    "xs = ys @ x # zs" "¬ P y (fold f ys acc)" "P y (f x (fold f ys acc))"
    by auto
  moreover from assms(4-) have "Q (fold f ys acc)" by (auto intro: fold_acc_preserv)
  moreover from xs = _ have "x  set xs"
    by auto
  ultimately show ?thesis using assms(3,6) by auto
qed

lemmas fold_evD2' = fold_evD2[where R = "λ _. True", simplified]

lemma filter_map_map_filter:
  "filter P (map f xs) = List.map_filter (λ x. let y = f x in if P y then Some y else None) xs"
  by (induction xs; simp add: Let_def List.map_filter_simps)

lemma distinct_map_filterI:
  "distinct (List.map_filter f xs)"
  if "x  set xs. y  set xs. a. f x = Some a  f y = Some a  x = y" "distinct xs"
  using that by (induction xs) (auto simp: map_filter_simps set_map_filter split: option.split)

lemma filter_eqI:
  assumes
    "subseq ys xs" "x  set ys. P x"
    "zs. subseq zs xs  length zs > length ys  ( x  set zs. ¬ P x)"
  shows "filter P xs = ys"
  using assms
proof (induction xs arbitrary: ys rule: list.induct)
  case Nil
  then show ?case
    by - (cases ys; simp)
next
  case (Cons x xs)
  show ?case
  proof (cases "P x")
    case True
    show ?thesis
    proof (cases ys)
      case Nil
      have "subseq [x] (x # xs)"
        by auto
      with Cons.prems Nil P x show ?thesis
        by fastforce
    next
      case (Cons y ys')
      have "x = y"
      proof (rule ccontr)
        assume "x  y"
        with subseq ys (x # xs) ys = _ have "subseq (x # ys) (x # xs)"
          by simp
        with Cons.prems(2-) P x show False
          by fastforce
      qed
      have "xset zs. ¬ P x" if "subseq zs xs" and "length ys' < length zs" for zs
      proof -
        from subseq zs xs have "subseq (x # zs) (x # xs)"
          by simp
        with length ys' < length zs Cons.prems(3) ys = _ have "xset (x # zs). ¬ P x"
          by (intro Cons.prems(3)[rule_format]; simp)
        with P x show ?thesis
          by auto
      qed
      with Cons.prems P x ys = _ x = y show ?thesis
        by (auto intro!: Cons.IH)
    qed
  next
    case False
    with Cons.prems show ?thesis
      by (cases ys) (auto split: if_split_asm intro!: Cons.IH)
  qed
qed

lemma filter_greatest_subseqD:
  " x  set zs. ¬ P x" if "subseq zs xs" "length zs > length (filter P xs)"
  using that by (metis filter_id_conv not_subseq_length subseq_filter)

lemma filter_eq_iff_greatest_subseq:
  "filter P xs = ys 
  subseq ys xs  (x  set ys. P x) 
  (zs. subseq zs xs  length zs > length ys  ( x  set zs. ¬ P x))"
  using filter_greatest_subseqD filter_eqI by auto

lemma subseq_subsetD:
  "set xs  set ys" if "subseq xs ys"
  using that
  by (intro subsetI) (unfold subseq_singleton_left[symmetric], erule subseq_order.trans)

lemma subseq_distinct:
  "distinct xs" if "distinct ys" "subseq xs ys"
  using subseqs_distinctD that by simp

lemma finite_subseqs:
  "finite {xs. subseq xs ys}" (is "finite ?S")
proof -
  have "?S  {xs. set xs  set ys  length xs  length ys}"
    using not_subseq_length by (force dest: subseq_subsetD)
  also have "finite "
    by (auto intro: finite_lists_length_le)
  finally (finite_subset) show ?thesis .
qed

lemma filter_distinct_eqI:
  assumes
    "subseq ys xs" "x  set ys. P x" "x  set xs. x  set ys  ¬ P x" "distinct xs"
  shows "filter P xs = ys"
proof (intro filter_eqI, safe)
  fix zs assume prems: "subseq zs xs" "length ys < length zs"
  obtain x where "x  set zs" "x  set ys"
  proof (atomize_elim, rule ccontr)
    assume "x. x  set zs  x  set ys"
    then have "set zs  set ys"
      by auto
    moreover from prems assms have "distinct zs" "distinct ys"
      by (blast intro: subseq_distinct)+
    ultimately show False
      using length ys < length zs
      by (auto dest: card_mono[rotated] simp: distinct_card[symmetric])
  qed
  with prems assms show "xset zs. ¬ P x"
    by (auto 4 3 dest: subseq_subsetD)
qed (use assms in blast)+

lemma subseq_sorted_wrt:
  "sorted_wrt R xs" if "sorted_wrt R ys" "subseq xs ys"
  using that
  by (induction xs arbitrary: ys)
     (auto 0 4 dest: subseq_subsetD list_emb_ConsD subseq_Cons' simp: sorted_wrt_append)

lemma subseq_sorted:
  "sorted xs" if "sorted ys" "subseq xs ys"
  using that by (rule subseq_sorted_wrt)

lemma sorted_distinct_subset_subseqI:
  assumes "sorted xs" "distinct xs" "sorted ys" "set xs  set ys"
  shows "subseq xs ys"
  using assms
proof (induction ys arbitrary: xs)
  case Nil
  then show ?case
    by simp
next
  case (Cons y ys xs)
  from Cons.prems show ?case
    by (cases xs; simp) (safe; rule Cons.IH; auto 4 4)
qed

lemma sorted_distinct_subseq_iff:
  assumes "sorted ys" "distinct ys"
  shows "subseq xs ys  (sorted xs  distinct xs  set xs  set ys)"
  using assms
  by safe
     (erule
       subseq_subsetD[THEN subsetD] sorted_distinct_subset_subseqI subseq_distinct subseq_sorted;
       assumption
     )+

lemma subseq_mapE:
  assumes "subseq xs (map f ys)"
  obtains xs' where "subseq xs' ys" "map f xs' = xs"
  using assms
  by (induct x1  xs x2  "map f ys" arbitrary: xs ys rule: list_emb.induct)
     (auto, metis map_consI(1) subseq_Cons2)

lemma list_all2_map_fst_aux:
  assumes "list_all2 (λx y. x  Pair y ` (zs y)) xs ys"
  shows "list_all2 (=) (map fst xs) ys"
  using assms by (smt fstI imageE list.rel_mono_strong list_all2_map1)

lemma list_all2_fst_aux:
  "map fst xs = ys" if "list_all2 (λx y. fst x = y) xs ys"
  using that by (induction) auto

text ‹Stronger version of @{thm Map.map_of_mapk_SomeI}
theorem map_of_mapk_SomeI':
  assumes "inj_on f (fst ` set t)"
    and "map_of t k = Some x"
  shows "map_of (map (λ(k, y). (f k, g y)) t) (f k) = Some (g x)"
  using assms
  apply (induction t)
   apply (solves simp)
  apply (clarsimp split: if_split_asm)
  apply (metis DiffI imageI img_fst map_of_SomeD singletonD)
  done

theorem map_of_mapk_SomeI:
  assumes "inj f"
    and "map_of t k = Some x"
  shows "map_of (map (λ(k, y). (f k, g y)) t) (f k) = Some (g x)"
  using assms by - (rule map_of_mapk_SomeI', erule inj_on_subset, auto)

lemma list_all2_map_eq_iff:
  "list_all2 (λx y. f x = g y) xs ys  map f xs = map g ys"
proof
  assume "list_all2 (λx y. f x = g y) xs ys"
  then show "map f xs = map g ys"
    by induction auto
next
  assume "map f xs = map g ys"
  then have "length xs = length ys"
    by (rule map_eq_imp_length_eq)
  then show "list_all2 (λx y. f x = g y) xs ys"
    using map f xs = _ by (induction rule: list_induct2; simp)
qed

end