Theory Prelims

(* Author: Alexander Maletzky *)

section ‹Preliminaries›

theory Prelims
  imports Polynomials.Utils Groebner_Bases.General
begin

subsection ‹Lists›

subsubsection ‹Sequences of Lists›

lemma list_seq_length_mono:
  fixes seq :: "nat  'a list"
  assumes "i. (x. seq (Suc i) = x # seq i)" and "i < j"
  shows "length (seq i) < length (seq j)"
proof -
  from assms(2) obtain k where "j = Suc (i + k)" using less_iff_Suc_add by auto
  show ?thesis unfolding j = Suc (i + k)
  proof (induct k)
    case 0
    from assms(1) obtain x where eq: "seq (Suc i) = x # seq i" ..
    show ?case by (simp add: eq)
  next
    case (Suc k)
    from assms(1) obtain x where "seq (Suc (i + Suc k)) = x # seq (i + Suc k)" ..
    hence eq: "seq (Suc (Suc (i + k))) = x # seq (Suc (i + k))" by simp
    note Suc
    also have "length (seq (Suc (i + k))) < length (seq (Suc (i + Suc k)))" by (simp add: eq)
    finally show ?case .
  qed
qed

corollary list_seq_length_mono_weak:
  fixes seq :: "nat  'a list"
  assumes "i. (x. seq (Suc i) = x # seq i)" and "i  j"
  shows "length (seq i)  length (seq j)"
proof (cases "i = j")
  case True
  thus ?thesis by simp
next
  case False
  with assms(2) have "i < j" by simp
  with assms(1) have "length (seq i) < length (seq j)" by (rule list_seq_length_mono)
  thus ?thesis by simp
qed

lemma list_seq_indexE_length:
  fixes seq :: "nat  'a list"
  assumes "i. (x. seq (Suc i) = x # seq i)"
  obtains j where "i < length (seq j)"
proof (induct i arbitrary: thesis)
  case 0
  have "0  length (seq 0)" by simp
  also from assms lessI have "... < length (seq (Suc 0))" by (rule list_seq_length_mono)
  finally show ?case by (rule 0)
next
  case (Suc i)
  obtain j where "i < length (seq j)" by (rule Suc(1))
  hence "Suc i  length (seq j)" by simp
  also from assms lessI have "... < length (seq (Suc j))" by (rule list_seq_length_mono)
  finally show ?case by (rule Suc(2))
qed

lemma list_seq_nth:
  fixes seq :: "nat  'a list"
  assumes "i. (x. seq (Suc i) = x # seq i)" and "i < length (seq j)" and "j  k"
  shows "rev (seq k) ! i = rev (seq j) ! i"
proof -
  from assms(3) obtain l where "k = j + l" using nat_le_iff_add by blast
  show ?thesis unfolding k = j + l
  proof (induct l)
    case 0
    show ?case by simp
  next
    case (Suc l)
    note assms(2)
    also from assms(1) le_add1 have "length (seq j)  length (seq (j + l))"
      by (rule list_seq_length_mono_weak)
    finally have i: "i < length (seq (j + l))" .
    from assms(1) obtain x where "seq (Suc (j + l)) = x # seq (j + l)" ..
    thus ?case by (simp add: nth_append i Suc)
  qed
qed

corollary list_seq_nth':
  fixes seq :: "nat  'a list"
  assumes "i. (x. seq (Suc i) = x # seq i)" and "i < length (seq j)" and "i < length (seq k)"
  shows "rev (seq k) ! i = rev (seq j) ! i"
proof (rule linorder_cases)
  assume "j < k"
  hence "j  k" by simp
  with assms(1, 2) show ?thesis by (rule list_seq_nth)
next
  assume "k < j"
  hence "k  j" by simp
  with assms(1, 3) have "rev (seq j) ! i = rev (seq k) ! i" by (rule list_seq_nth)
  thus ?thesis by (rule HOL.sym)
next
  assume "j = k"
  thus ?thesis by simp
qed

subsubsection @{const filter}

lemma filter_merge_wrt_1:
  assumes "y. y  set ys  P y  False"
  shows "filter P (merge_wrt rel xs ys) = filter P xs"
  using assms
proof (induct rel xs ys rule: merge_wrt.induct)
  case (1 rel xs)
  show ?case by simp
next
  case (2 rel y ys)
  hence "P y  False" and "z. z  set ys  P z  False" by auto
  thus ?case by (auto simp: filter_empty_conv)
next
  case (3 rel x xs y ys)
  hence "¬ P y" and x: "z. z  set ys  P z  False" by auto
  have a: "filter P (merge_wrt rel xs ys) = filter P xs" if "x = y" using that x by (rule 3(1))
  have b: "filter P (merge_wrt rel xs (y # ys)) = filter P xs" if "x  y" and "rel x y"
    using that 3(4) by (rule 3(2))
  have c: "filter P (merge_wrt rel (x # xs) ys) = filter P (x # xs)" if "x  y" and "¬ rel x y"
    using that x by (rule 3(3))
  show ?case by (simp add: a b c ¬ P y)
qed

lemma filter_merge_wrt_2:
  assumes "x. x  set xs  P x  False"
  shows "filter P (merge_wrt rel xs ys) = filter P ys"
  using assms
proof (induct rel xs ys rule: merge_wrt.induct)
  case (1 rel xs)
  thus ?case by (auto simp: filter_empty_conv)
next
  case (2 rel y ys)
  show ?case by simp
next
  case (3 rel x xs y ys)
  hence "¬ P x" and x: "z. z  set xs  P z  False" by auto
  have a: "filter P (merge_wrt rel xs ys) = filter P ys" if "x = y" using that x by (rule 3(1))
  have b: "filter P (merge_wrt rel xs (y # ys)) = filter P (y # ys)" if "x  y" and "rel x y"
    using that x by (rule 3(2))
  have c: "filter P (merge_wrt rel (x # xs) ys) = filter P ys" if "x  y" and "¬ rel x y"
    using that 3(4) by (rule 3(3))
  show ?case by (simp add: a b c ¬ P x)
qed

lemma length_filter_le_1:
  assumes "length (filter P xs)  1" and "i < length xs" and "j < length xs"
    and "P (xs ! i)" and "P (xs ! j)"
  shows "i = j"
proof -
  have *: thesis if "a < b" and "b < length xs"
    and "as bs cs. as @ ((xs ! a) # (bs @ ((xs ! b) # cs))) = xs  thesis" for a b thesis
  proof (rule that(3))
    from that(1, 2) have 1: "a < length xs" by simp
    with that(1, 2) have 2: "b - Suc a < length (drop (Suc a) xs)" by simp
    from that(1) a < length xs have eq: "xs ! b = drop (Suc a) xs ! (b - Suc a)" by simp
    show "(take a xs) @ ((xs ! a) # ((take (b - Suc a) (drop (Suc a) xs)) @ ((xs ! b) #
                  drop (Suc (b - Suc a)) (drop (Suc a) xs)))) = xs"
      by (simp only: eq id_take_nth_drop[OF 1, symmetric] id_take_nth_drop[OF 2, symmetric])
  qed
  show ?thesis
  proof (rule linorder_cases)
    assume "i < j"
    then obtain as bs cs where "as @ ((xs ! i) # (bs @ ((xs ! j) # cs))) = xs"
      using assms(3) by (rule *)
    hence "filter P xs = filter P (as @ ((xs ! i) # (bs @ ((xs ! j) # cs))))" by simp
    also from assms(4, 5) have "... = (filter P as) @ ((xs ! i) # ((filter P bs) @ ((xs ! j) # (filter P cs))))"
      by simp
    finally have "¬ length (filter P xs)  1" by simp
    thus ?thesis using assms(1) ..
  next
    assume "j < i"
    then obtain as bs cs where "as @ ((xs ! j) # (bs @ ((xs ! i) # cs))) = xs"
      using assms(2) by (rule *)
    hence "filter P xs = filter P (as @ ((xs ! j) # (bs @ ((xs ! i) # cs))))" by simp
    also from assms(4, 5) have "... = (filter P as) @ ((xs ! j) # ((filter P bs) @ ((xs ! i) # (filter P cs))))"
      by simp
    finally have "¬ length (filter P xs)  1" by simp
    thus ?thesis using assms(1) ..
  qed
qed

lemma length_filter_eq [simp]: "length (filter ((=) x) xs) = count_list xs x"
  by (induct xs, simp_all)

subsubsection @{const drop}

lemma nth_in_set_dropI:
  assumes "j  i" and "i < length xs"
  shows "xs ! i  set (drop j xs)"
  using assms
proof (induct xs arbitrary: i j)
  case Nil
  thus ?case by simp
next
  case (Cons x xs)
  show ?case
  proof (cases j)
    case 0
    with Cons(3) show ?thesis by (metis drop0 nth_mem)
  next
    case (Suc j0)
    with Cons(2) Suc_le_D obtain i0 where i: "i = Suc i0" by blast
    with Cons(2) have "j0  i0" by (simp add: j = Suc j0)
    moreover from Cons(3) have "i0 < length xs" by (simp add: i)
    ultimately have "xs ! i0  set (drop j0 xs)" by (rule Cons(1))
    thus ?thesis by (simp add: i j = Suc j0)
  qed
qed

subsubsection @{const count_list}

lemma count_list_upt [simp]: "count_list [a..<b] x = (if a  x  x < b then 1 else 0)"
proof (cases "a  b")
  case True
  then obtain k where "b = a + k" using le_Suc_ex by blast
  show ?thesis unfolding b = a + k by (induct k, simp_all)
next
  case False
  thus ?thesis by simp
qed

subsubsection @{const sorted_wrt}

lemma sorted_wrt_upt_iff: "sorted_wrt rel [a..<b]  (i j. a  i  i < j  j < b  rel i j)"
proof (cases "a  b")
  case True
  then obtain k where "b = a + k" using le_Suc_ex by blast
  show ?thesis unfolding b = a + k
  proof (induct k)
    case 0
    show ?case by simp
  next
    case (Suc k)
    show ?case
    proof (simp add: sorted_wrt_append Suc, intro iffI allI ballI impI conjI)
      fix i j
      assume "(ia. j>i. j < a + k  rel i j)  (x{a..<a + k}. rel x (a + k))"
      hence 1: "i' j'. a  i'  i' < j'  j' < a + k  rel i' j'"
        and 2: "x. a  x  x < a + k  rel x (a + k)" by simp_all
      assume "a  i" and "i < j"
      assume "j < Suc (a + k)"
      hence "j < a + k  j = a + k" by auto
      thus "rel i j"
      proof
        assume "j < a + k"
        with a  i i < j show ?thesis by (rule 1)
      next
        assume "j = a + k"
        from a  i i < j show ?thesis unfolding j = a + k by (rule 2)
      qed
    next
      fix i j
      assume "ia. j>i. j < Suc (a + k)  rel i j" and "a  i" and "i < j" and "j < a + k"
      thus "rel i j" by simp
    next
      fix x
      assume "x  {a..<a + k}"
      hence "a  x" and "x < a + k" by simp_all
      moreover assume "ia. j>i. j < Suc (a + k)  rel i j"
      ultimately show "rel x (a + k)" by simp
    qed
  qed
next
  case False
  thus ?thesis by simp
qed

subsubsection @{const insort_wrt} and @{const merge_wrt}

lemma map_insort_wrt:
  assumes "x. x  set xs  r2 (f y) (f x)  r1 y x"
  shows "map f (insort_wrt r1 y xs) = insort_wrt r2 (f y) (map f xs)"
  using assms
proof (induct xs)
  case Nil
  show ?case by simp
next
  case (Cons x xs)
  have "x  set (x # xs)" by simp
  hence "r2 (f y) (f x) = r1 y x" by (rule Cons(2))
  moreover have "map f (insort_wrt r1 y xs) = insort_wrt r2 (f y) (map f xs)"
  proof (rule Cons(1))
    fix x'
    assume "x'  set xs"
    hence "x'  set (x # xs)" by simp
    thus "r2 (f y) (f x') = r1 y x'" by (rule Cons(2))
  qed
  ultimately show ?case by simp
qed

lemma map_merge_wrt:
  assumes "f ` set xs  f ` set ys = {}"
    and "x y. x  set xs  y  set ys  r2 (f x) (f y)  r1 x y"
  shows "map f (merge_wrt r1 xs ys) = merge_wrt r2 (map f xs) (map f ys)"
  using assms
proof (induct r1 xs ys rule: merge_wrt.induct)
  case (1 uu xs)
  show ?case by simp
next
  case (2 r1 v va)
  show ?case by simp
next
  case (3 r1 x xs y ys)
  from 3(4) have "f x  f y" and 1: "f ` set xs  f ` set (y # ys) = {}"
    and 2: "f ` set (x # xs)  f ` set ys = {}" by auto
  from this(1) have "x  y" by auto
  have eq2: "map f (merge_wrt r1 xs (y # ys)) = merge_wrt r2 (map f xs) (map f (y # ys))"
    if "r1 x y" using x  y that 1
  proof (rule 3(2))
    fix a b
    assume "a  set xs"
    hence "a  set (x # xs)" by simp
    moreover assume "b  set (y # ys)"
    ultimately show "r2 (f a) (f b)  r1 a b" by (rule 3(5))
  qed
  have eq3: "map f (merge_wrt r1 (x # xs) ys) = merge_wrt r2 (map f (x # xs)) (map f ys)"
    if "¬ r1 x y" using x  y that 2
  proof (rule 3(3))
    fix a b
    assume "a  set (x # xs)"
    assume "b  set ys"
    hence "b  set (y # ys)" by simp
    with a  set (x # xs) show "r2 (f a) (f b)  r1 a b" by (rule 3(5))
  qed
  have eq4: "r2 (f x) (f y)  r1 x y" by (rule 3(5), simp_all)
  show ?case by (simp add: eq2 eq3 eq4 f x  f y x  y)
qed

subsection ‹Recursive Functions›

locale recursive =
  fixes h' :: "'b  'b"
  fixes b :: 'b
  assumes b_fixpoint: "h' b = b"
begin

context
  fixes Q :: "'a  bool"
  fixes g :: "'a  'b"
  fixes h :: "'a  'a"
begin

function (domintros) recfun_aux :: "'a  'b" where
  "recfun_aux x = (if Q x then g x else h' (recfun_aux (h x)))"
  by pat_completeness auto

lemmas [induct del] = recfun_aux.pinduct

definition dom :: "'a  bool"
  where "dom x  (k. Q ((h ^^ k) x))"

lemma domI:
  assumes "¬ Q x  dom (h x)"
  shows "dom x"
proof (cases "Q x")
  case True
  hence "Q ((h ^^ 0) x)" by simp
  thus ?thesis unfolding dom_def ..
next
  case False
  hence "dom (h x)" by (rule assms)
  then obtain k where "Q ((h ^^ k) (h x))" unfolding dom_def ..
  hence "Q ((h ^^ (Suc k)) x)" by (simp add: funpow_swap1)
  thus ?thesis unfolding dom_def ..
qed

lemma domD:
  assumes "dom x" and "¬ Q x"
  shows "dom (h x)"
proof -
  from assms(1) obtain k where *: "Q ((h ^^ k) x)" unfolding dom_def ..
  with assms(2) have "k  0" using funpow_0 by fastforce
  then obtain m where "k = Suc m" using nat.exhaust by blast
  with * have "Q ((h ^^ m) (h x))" by (simp add: funpow_swap1)
  thus ?thesis unfolding dom_def ..
qed

lemma recfun_aux_domI:
  assumes "dom x"
  shows "recfun_aux_dom x"
proof -
  from assms obtain k where "Q ((h ^^ k) x)" unfolding dom_def ..
  thus ?thesis
  proof (induct k arbitrary: x)
    case 0
    hence "Q x" by simp
    with recfun_aux.domintros show ?case by blast
  next
    case (Suc k)
    from Suc(2) have "Q ((h ^^ k) (h x))" by (simp add: funpow_swap1)
    hence "recfun_aux_dom (h x)" by (rule Suc(1))
    with recfun_aux.domintros show ?case by blast
  qed
qed

lemma recfun_aux_domD:
  assumes "recfun_aux_dom x"
  shows "dom x"
  using assms
proof (induct x rule: recfun_aux.pinduct)
  case (1 x)
  show ?case
  proof (cases "Q x")
    case True
    with domI show ?thesis by blast
  next
    case False
    hence "dom (h x)" by (rule 1(2))
    thus ?thesis using domI by blast
  qed
qed

corollary recfun_aux_dom_alt: "recfun_aux_dom = dom"
  by (auto dest: recfun_aux_domI recfun_aux_domD)

definition "fun" :: "'a  'b"
  where "fun x = (if recfun_aux_dom x then recfun_aux x else b)"

lemma simps: "fun x = (if Q x then g x else h' (fun (h x)))"
proof (cases "dom x")
  case True
  hence dom: "recfun_aux_dom x" by (rule recfun_aux_domI)
  show ?thesis
  proof (cases "Q x")
    case True
    with dom show ?thesis by (simp add: fun_def recfun_aux.psimps)
  next
    case False
    have "recfun_aux_dom (h x)" by (rule recfun_aux_domI, rule domD, fact True, fact False)
    thus ?thesis by (simp add: fun_def dom False recfun_aux.psimps)
  qed
next
  case False
  moreover have "¬ Q x"
  proof
    assume "Q x"
    hence "dom x" using domI by blast
    with False show False ..
  qed
  moreover have "¬ dom (h x)"
  proof
    assume "dom (h x)"
    hence "dom x" using domI by blast
    with False show False ..
  qed
  ultimately show ?thesis by (simp add: recfun_aux_dom_alt fun_def b_fixpoint split del: if_split)
qed

lemma eq_fixpointI: "¬ dom x  fun x = b"
  by (simp add: fun_def recfun_aux_dom_alt)

lemma pinduct: "dom x  (x. dom x  (¬ Q x  P (h x))  P x)  P x"
  unfolding recfun_aux_dom_alt[symmetric] by (fact recfun_aux.pinduct)

end

end (* recursive *)

interpretation tailrec: recursive "λx. x" undefined
  by (standard, fact refl)

subsection ‹Binary Relations›

lemma almost_full_on_Int:
  assumes "almost_full_on P1 A1" and "almost_full_on P2 A2"
  shows "almost_full_on (λx y. P1 x y  P2 x y) (A1  A2)" (is "almost_full_on ?P ?A")
proof (rule almost_full_onI)
  fix f :: "nat  'a"
  assume a: "i. f i  ?A"
  define g where "g = (λi. (f i, f i))"
  from assms have "almost_full_on (prod_le P1 P2) (A1 × A2)" by (rule almost_full_on_Sigma)
  moreover from a have "i. g i  A1 × A2" by (simp add: g_def)
  ultimately obtain i j where "i < j" and "prod_le P1 P2 (g i) (g j)" by (rule almost_full_onD)
  from this(2) have "?P (f i) (f j)" by (simp add: g_def prod_le_def)
  with i < j show "good ?P f" by (rule goodI)
qed

corollary almost_full_on_same:
  assumes "almost_full_on P1 A" and "almost_full_on P2 A"
  shows "almost_full_on (λx y. P1 x y  P2 x y) A"
proof -
  from assms have "almost_full_on (λx y. P1 x y  P2 x y) (A  A)" by (rule almost_full_on_Int)
  thus ?thesis by simp
qed

context ord
begin

definition is_le_rel :: "('a  'a  bool)  bool"
  where "is_le_rel rel = (rel = (=)  rel = (≤)  rel = (<))"

lemma is_le_relI [simp]: "is_le_rel (=)" "is_le_rel (≤)" "is_le_rel (<)"
  by (simp_all add: is_le_rel_def)

lemma is_le_relE:
  assumes "is_le_rel rel"
  obtains "rel = (=)" | "rel = (≤)" | "rel = (<)"
  using assms unfolding is_le_rel_def by blast

end (* ord *)

context preorder
begin

lemma is_le_rel_le:
  assumes "is_le_rel rel"
  shows "rel x y  x  y"
  using assms by (rule is_le_relE, auto dest: less_imp_le)

lemma is_le_rel_trans:
  assumes "is_le_rel rel"
  shows "rel x y  rel y z  rel x z"
  using assms by (rule is_le_relE, auto dest: order_trans less_trans)

lemma is_le_rel_trans_le_left:
  assumes "is_le_rel rel"
  shows "x  y  rel y z  x  z"
  using assms by (rule is_le_relE, auto dest: order_trans le_less_trans less_imp_le)

lemma is_le_rel_trans_le_right:
  assumes "is_le_rel rel"
  shows "rel x y  y  z  x  z"
  using assms by (rule is_le_relE, auto dest: order_trans less_le_trans less_imp_le)

lemma is_le_rel_trans_less_left:
  assumes "is_le_rel rel"
  shows "x < y  rel y z  x < z"
  using assms by (rule is_le_relE, auto dest: less_le_trans less_imp_le)

lemma is_le_rel_trans_less_right:
  assumes "is_le_rel rel"
  shows "rel x y  y < z  x < z"
  using assms by (rule is_le_relE, auto dest: le_less_trans less_imp_le)

end (* preorder *)

context order
begin

lemma is_le_rel_distinct:
  assumes "is_le_rel rel"
  shows "rel x y  x  y  x < y"
  using assms by (rule is_le_relE, auto)

lemma is_le_rel_antisym:
  assumes "is_le_rel rel"
  shows "rel x y  rel y x  x = y"
  using assms by (rule is_le_relE, auto)

end (* order *)

end (* theory *)