Theory Basis
theory Basis
imports
Main
"HOL-Library.While_Combinator"
begin
section‹ Preliminaries ›
subsection‹ HOL Detritus ›
lemma Above_union:
shows "x ∈ Above r (X ∪ Y) ⟷ x ∈ Above r X ∧ x ∈ Above r Y"
unfolding Above_def by blast
lemma Above_Field:
assumes "x ∈ Above r X"
shows "x ∈ Field r"
using assms unfolding Above_def by blast
lemma AboveS_Field:
assumes "x ∈ AboveS r X"
shows "x ∈ Field r"
using assms unfolding AboveS_def by blast
lemma Above_Linear_singleton:
assumes "x ∈ Field r"
assumes "Linear_order r"
shows "x ∈ Above r {x}"
using assms unfolding Above_def order_on_defs by (force dest: refl_onD)
lemma subseqs_set:
assumes "y ∈ set (subseqs xs)"
shows "set y ⊆ set xs"
using assms by (metis Pow_iff image_eqI subseqs_powset)
primrec map_of_default :: "'v ⇒ ('k × 'v) list ⇒ 'k ⇒ 'v" where
"map_of_default v0 [] k = v0"
| "map_of_default v0 (kv # kvs) k = (if k = fst kv then snd kv else map_of_default v0 kvs k)"
lemmas set_elem_equalityI = Set.equalityI[OF Set.subsetI Set.subsetI]
lemmas total_onI = iffD2[OF total_on_def, rule_format]
lemma partial_order_on_acyclic:
assumes "partial_order_on A r"
shows "acyclic (r - Id)"
by (metis acyclic_irrefl assms irrefl_diff_Id partial_order_on_def preorder_on_def trancl_id trans_diff_Id)
lemma finite_Linear_order_induct[consumes 3, case_names step]:
assumes "Linear_order r"
assumes "x ∈ Field r"
assumes "finite r"
assumes step: "⋀x. ⟦x ∈ Field r; ⋀y. y ∈ aboveS r x ⟹ P y⟧ ⟹ P x"
shows "P x"
using assms(2)
proof(induct rule: wf_induct[of "r¯ - Id"])
from assms(1,3) show "wf (r¯ - Id)"
using linear_order_on_well_order_on linear_order_on_converse
unfolding well_order_on_def by blast
next
case (2 x) then show ?case
by - (rule step; auto simp: aboveS_def intro: FieldI2)
qed
text‹
We sometimes want a notion of monotonicity over some set.
›
definition mono_on :: "'a::order set ⇒ ('a ⇒ 'b::order) ⇒ bool" where
"mono_on A f = (∀x∈A. ∀y∈A. x ≤ y ⟶ f x ≤ f y)"
lemmas mono_onI = iffD2[OF mono_on_def, rule_format]
lemmas mono_onD = iffD1[OF mono_on_def, rule_format]
lemma mono_onE:
"⟦mono_on A f; x ∈ A; y ∈ A; x ≤ y; f x ≤ f y ⟹ thesis⟧ ⟹ thesis"
using mono_onD by blast
lemma mono_on_mono:
"mono_on UNIV = mono"
by (clarsimp simp: mono_on_def mono_def fun_eq_iff)
subsection‹ MaxR: maximum elements of linear orders ›
text‹
We generalize the existing @{const "max"} and @{const "Max"} functions
to work on orders defined over sets. See \S\ref{sec:cf-linear} for
choice-function related lemmas.
›
locale MaxR =
fixes r :: "'a::finite rel"
assumes r_Linear_order: "Linear_order r"
begin
text‹
The basic function chooses the largest of two elements:
›
definition maxR :: "'a ⇒ 'a ⇒ 'a" where
"maxR x y = (if (x, y) ∈ r then y else x)"
lemma maxR_domain:
shows "{x, y} ⊆ A ⟹ maxR x y ∈ A"
unfolding maxR_def by simp
lemma maxR_range:
shows "maxR x y ∈ {x, y}"
unfolding maxR_def by simp
lemma maxR_rangeD:
"maxR x y ≠ x ⟹ maxR x y = y"
"maxR x y ≠ y ⟹ maxR x y = x"
unfolding maxR_def by auto
lemma maxR_idem:
shows "maxR x x = x"
unfolding maxR_def by simp
lemma maxR_absorb2:
shows "(x, y) ∈ r ⟹ maxR x y = y"
unfolding maxR_def by simp
lemma maxR_absorb1:
shows "(y, x) ∈ r ⟹ maxR x y = x"
using r_Linear_order unfolding maxR_def by (simp add: order_on_defs antisym_def)
lemma maxR_assoc:
shows "{x,y,z} ⊆ Field r ⟹ maxR (maxR x y) z = maxR x (maxR y z)"
using r_Linear_order unfolding maxR_def by simp (metis order_on_defs(1-3) total_on_def trans_def)
lemma maxR_commute:
shows "{x,y} ⊆ Field r ⟹ maxR x y = maxR y x"
using r_Linear_order unfolding maxR_def by (fastforce simp: order_on_defs antisym_def total_on_def)
lemmas maxR_simps =
maxR_idem
maxR_absorb1
maxR_absorb2
text‹
We hoist this to finite sets using the @{const "Finite_Set.fold"}
combinator. For code generation purposes it seems inevitable that we
need to fuse the fold and filter into a single total recursive
definition.
›
definition MaxR_f :: "'a ⇒ 'a option ⇒ 'a option" where
"MaxR_f x acc = (if x ∈ Field r then Some (case acc of None ⇒ x | Some y ⇒ maxR x y) else acc)"
interpretation MaxR_f: comp_fun_idem MaxR_f
using %invisible r_Linear_order
by unfold_locales (fastforce simp: fun_eq_iff maxR_def MaxR_f_def order_on_defs total_on_def antisymD elim: transE split: option.splits)+
definition MaxR_opt :: "'a set ⇒ 'a option" where
MaxR_opt_eq_fold': "MaxR_opt A = Finite_Set.fold MaxR_f None A"
lemma empty [simp]:
shows "MaxR_opt {} = None"
by (simp add: MaxR_opt_eq_fold')
lemma
shows insert: "MaxR_opt (insert x A) = (if x ∈ Field r then Some (case MaxR_opt A of None ⇒ x | Some y ⇒ maxR x y) else MaxR_opt A)"
and range_Some[rule_format]: "MaxR_opt A = Some a ⟶ a ∈ A ∩ Field r"
using finite[of A] by induct (auto simp: MaxR_opt_eq_fold' maxR_def MaxR_f_def split: option.splits)
lemma range_None:
assumes "MaxR_opt A = None"
shows "A ∩ Field r = {}"
using assms by (metis Int_iff insert all_not_in_conv insert_absorb option.simps(3))
lemma domain_empty:
assumes "A ∩ Field r = {}"
shows "MaxR_opt A = None"
using assms by (metis empty_iff option.exhaust range_Some)
lemma domain:
shows "MaxR_opt (A ∩ Field r) = MaxR_opt A"
using finite[of A] by induct (simp_all add: insert)
lemmas MaxR_opt_code = MaxR_opt_eq_fold'[where A="set A", unfolded MaxR_f.fold_set_fold] for A
lemma range:
shows "MaxR_opt A ∈ Some ` (A ∩ Field r) ∪ {None}"
using range_Some notin_range_Some by fastforce
lemma union:
shows "MaxR_opt (A ∪ B) = (case MaxR_opt A of None ⇒ MaxR_opt B | Some mA ⇒ Some (case MaxR_opt B of None ⇒ mA | Some mB ⇒ maxR mA mB))"
using finite[of A] by induct (auto simp: maxR_assoc insert dest!: range_Some split: option.splits)
lemma mono:
assumes "MaxR_opt A = Some x"
shows "∃y. MaxR_opt (A ∪ B) = Some y ∧ (x, y) ∈ r"
using finite[of B]
proof induct
case empty with assms show ?case
using range_Some underS_incl_iff[OF r_Linear_order] by fastforce
next
note ins = insert
case (insert b B) with assms r_Linear_order show ?case
unfolding order_on_defs total_on_def by (fastforce simp: ins maxR_def elim: transE intro: FieldI1)
qed
declare [[simproc del: eliminate_false_implies]]
lemma MaxR_opt_is_greatest:
assumes "MaxR_opt A = Some x"
assumes "y ∈ A ∩ Field r"
shows "(y, x) ∈ r"
using finite[of A] assms
proof(induct arbitrary: x)
note ins = insert
case (insert a A)
show ?case
proof (cases "y = x")
case True
thus "(y, x) ∈ r"
using r_Linear_order insert by (auto simp: order_on_defs refl_on_def)
next
case False
show "(y, x) ∈ r"
proof (rule ccontr)
assume "(y, x) ∉ r"
from insert have "x ∈ Field r" "y ∈ Field r"
by (auto simp: maxR_def ins dest!: range_None range_Some split: if_splits option.splits)
from ‹(y, x) ∉ r› and ‹y ≠ x› and insert obtain z where z: "(x, z) ∉ r" "(y, z) ∈ r" "z ∈ Field r"
by (auto simp: maxR_def ins dest!: range_None range_Some split: if_splits option.splits)
have "(x, y) ∈ r"
using r_Linear_order ‹(y, x) ∉ r› ‹x ∈ Field r› ‹y ∈ Field r› ‹y ≠ x›
by (auto simp: order_on_defs total_on_def)
have "trans r"
using r_Linear_order by (auto simp: order_on_defs)
from this and ‹(x, y) ∈ r› and ‹(y, z) ∈ r› have "(x, z) ∈ r"
by (rule transD)
with ‹(x, z) ∉ r› show False by contradiction
qed
qed
qed simp
lemma greatest_is_MaxR_opt:
assumes "x ∈ A ∩ Field r"
assumes "∀y ∈ A ∩ Field r. (y, x) ∈ r"
shows "MaxR_opt A = Some x"
using finite[of A] assms
proof(induct arbitrary: x)
note ins = insert
case (insert a A) then show ?case
using maxR_absorb1 maxR_absorb2
by (fastforce simp: maxR_def ins dest: range_None range_Some split: option.splits)
qed simp
lemma subset:
assumes "set_option (MaxR_opt B) ⊆ A"
assumes "A ⊆ B"
shows "MaxR_opt B = MaxR_opt A"
using union[where A=A and B="B-A"] range[of "B - A"] assms
by (auto simp: Un_absorb1 finite_subset maxR_def split: option.splits)
end
interpretation MaxR_empty: MaxR "{}"
by unfold_locales simp
interpretation MaxR_singleton: MaxR "{(x,x)}" for x
by unfold_locales simp
lemma MaxR_r_domain [iff]:
assumes "MaxR r"
shows "MaxR (Restr r A)"
using assms Linear_order_Restr unfolding MaxR_def by blast
subsection‹ Linear orders from lists ›
text‹
Often the easiest way to specify a concrete linear order is with a
list. Here these run from greatest to least.
›
primrec linord_of_listP :: "'a ⇒ 'a ⇒ 'a list ⇒ bool" where
"linord_of_listP x y [] ⟷ False"
| "linord_of_listP x y (z # zs) ⟷ (z = y ∧ x ∈ set (z # zs)) ∨ linord_of_listP x y zs"
definition linord_of_list :: "'a list ⇒ 'a rel" where
"linord_of_list xs ≡ {(x, y). linord_of_listP x y xs}"
lemma linord_of_list_linord_of_listP:
shows "xy ∈ linord_of_list xs ⟷ linord_of_listP (fst xy) (snd xy) xs"
unfolding linord_of_list_def split_def by simp
lemma linord_of_listP_linord_of_list:
shows "linord_of_listP x y xs ⟷ (x, y) ∈ linord_of_list xs"
unfolding linord_of_list_def by simp
lemma linord_of_listP_empty:
shows "(∀x y. ¬linord_of_listP x y xs) ⟷ xs = []"
by (metis linord_of_listP.simps list.exhaust list.set_intros(1))
lemma linord_of_listP_domain:
assumes "linord_of_listP x y xs"
shows "x ∈ set xs ∧ y ∈ set xs"
using assms by (induct xs) auto
lemma linord_of_list_empty[iff]:
"linord_of_list [] = {}"
"linord_of_list xs = {} ⟷ xs = []"
unfolding linord_of_list_def by (simp_all add: linord_of_listP_empty)
lemma linord_of_list_singleton:
"(x, y) ∈ linord_of_list [z] ⟷ x = z ∧ y = z"
by (force simp: linord_of_list_linord_of_listP)
lemma linord_of_list_range:
"linord_of_list xs ⊆ set xs × set xs"
unfolding linord_of_list_def by (induct xs) auto
lemma linord_of_list_Field [simp]:
"Field (linord_of_list xs) = set xs"
unfolding linord_of_list_def by (induct xs) (auto simp: Field_def)
lemma linord_of_listP_append:
"linord_of_listP x y (xs @ ys) ⟷ linord_of_listP x y xs ∨ linord_of_listP x y ys ∨ (y ∈ set xs ∧ x ∈ set ys)"
by (induct xs) auto
lemma linord_of_list_append:
"(x, y) ∈ linord_of_list (xs @ ys) ⟷ (x, y) ∈ linord_of_list xs ∨ (x, y) ∈ linord_of_list ys ∨ (y ∈ set xs ∧ x ∈ set ys)"
unfolding linord_of_list_def by (simp add: linord_of_listP_append)
lemma linord_of_list_refl_on:
shows "refl_on (set xs) (linord_of_list xs)"
unfolding linord_of_list_def
by (induct xs) (auto intro!: refl_onI simp: refl_onD1 refl_onD2 dest: refl_onD subsetD[OF linord_of_list_range])
lemma linord_of_list_trans:
assumes "distinct xs"
shows "trans (linord_of_list xs)"
using assms unfolding linord_of_list_def
by (induct xs) (auto intro!: transI dest: linord_of_listP_domain elim: transE)
lemma linord_of_list_antisym:
assumes "distinct xs"
shows "antisym (linord_of_list xs)"
using assms unfolding linord_of_list_def
by (induct xs) (auto intro!: antisymI dest: linord_of_listP_domain simp: antisymD)
lemma linord_of_list_total_on:
shows "total_on (set xs) (linord_of_list xs)"
unfolding total_on_def linord_of_list_def by (induct xs) auto
lemma linord_of_list_Restr:
assumes "x ∉ C"
notes in_set_remove1[simp del]
shows "Restr (linord_of_list (remove1 x xs)) C = Restr (linord_of_list xs) C"
using assms unfolding linord_of_list_def by (induct xs) (auto iff: in_set_remove1)
lemma linord_of_list_nth:
assumes "(xs ! i, xs ! j) ∈ linord_of_list xs"
assumes "i < length xs" "j < length xs"
assumes "distinct xs"
shows "j ≤ i"
using %invisible assms
proof(induct xs arbitrary: i j)
case (Cons x xs i j) show ?case
proof(cases "i < length xs")
case True with Cons show ?thesis
by (auto simp: linord_of_list_linord_of_listP nth_equal_first_eq less_Suc_eq_0_disj linord_of_listP_domain)
next
case False with Cons show ?thesis by fastforce
qed
qed simp
text‹›
lemma linord_of_list_Linear_order:
assumes "distinct xs"
assumes "ys = set xs"
shows "linear_order_on ys (linord_of_list xs)"
using %invisible assms linord_of_list_range linord_of_list_refl_on linord_of_list_trans linord_of_list_antisym linord_of_list_total_on
unfolding order_on_defs by force
text‹
Every finite linear order is generated by a list.
›
inductive sorted_on :: "'a rel ⇒ 'a list ⇒ bool" where
Nil [iff]: "sorted_on r []"
| Cons [intro!]: "⟦x ∈ Field r; ∀y∈set xs. (x, y) ∈ r; sorted_on r xs⟧ ⟹ sorted_on r (x # xs)"
inductive_cases sorted_on_inv[elim!]:
"sorted_on r []"
"sorted_on r (x # xs)"
primrec insort_key_on :: "'a rel ⇒ ('b ⇒ 'a) ⇒ 'b ⇒ 'b list ⇒ 'b list" where
"insort_key_on r f x [] = [x]"
| "insort_key_on r f x (y # ys) =
(if (f x, f y) ∈ r then (x # y # ys) else y # insort_key_on r f x ys)"
definition sort_key_on :: "'a rel ⇒ ('b ⇒ 'a) ⇒ 'b list ⇒ 'b list" where
"sort_key_on r f xs = foldr (insort_key_on r f) xs []"
definition insort_insert_key_on :: "'a rel ⇒ ('b ⇒ 'a) ⇒ 'b ⇒ 'b list ⇒ 'b list" where
"insort_insert_key_on r f x xs =
(if f x ∈ f ` set xs then xs else insort_key_on r f x xs)"
abbreviation "sort_on r ≡ sort_key_on r (λx. x)"
abbreviation "insort_on r ≡ insort_key_on r (λx. x)"
abbreviation "insort_insert_on r ≡ insort_insert_key_on r (λx. x)"
context
fixes r :: "'a rel"
assumes "Linear_order r"
begin
lemma sorted_on_single [iff]:
shows "sorted_on r [x] ⟷ x ∈ Field r"
by (metis empty_iff list.distinct(1) list.set(1) nth_Cons_0 sorted_on.simps)
lemma sorted_on_many:
assumes "(x, y) ∈ r"
assumes "sorted_on r (y # zs)"
shows "sorted_on r (x # y # zs)"
using assms ‹Linear_order r› unfolding order_on_defs by (auto elim: transE intro: FieldI1)
lemma sorted_on_Cons:
shows "sorted_on r (x # xs) ⟷ (x ∈ Field r ∧ sorted_on r xs ∧ (∀y∈set xs. (x, y) ∈ r))"
using ‹Linear_order r› unfolding order_on_defs by (induct xs arbitrary: x) (auto elim: transE)
lemma sorted_on_distinct_set_unique:
assumes "sorted_on r xs" "distinct xs" "sorted_on r ys" "distinct ys" "set xs = set ys"
shows "xs = ys"
proof -
from assms have 1: "length xs = length ys" by (auto dest!: distinct_card)
from assms show ?thesis
proof(induct rule: list_induct2[OF 1])
case (2 x xs y ys) with ‹Linear_order r› show ?case
unfolding order_on_defs
by (simp add: sorted_on_Cons) (metis antisymD insertI1 insert_eq_iff)
qed simp
qed
lemma set_insort_on:
shows "set (insort_key_on r f x xs) = insert x (set xs)"
by (induct xs) auto
lemma sort_key_on_simps [simp]:
shows "sort_key_on r f [] = []"
"sort_key_on r f (x#xs) = insort_key_on r f x (sort_key_on r f xs)"
by (simp_all add: sort_key_on_def)
lemma set_sort_on [simp]:
shows "set (sort_key_on r f xs) = set xs"
by (induct xs) (simp_all add: set_insort_on)
lemma distinct_insort_on:
shows "distinct (insort_key_on r f x xs) = (x ∉ set xs ∧ distinct xs)"
by(induct xs) (auto simp: set_insort_on)
lemma distinct_sort_on [simp]:
shows "distinct (sort_key_on r f xs) = distinct xs"
by (induct xs) (simp_all add: distinct_insort_on)
lemma sorted_on_insort_key_on:
assumes "f ` set (x # xs) ⊆ Field r"
shows "sorted_on r (map f (insort_key_on r f x xs)) = sorted_on r (map f xs)"
using assms
proof(induct xs)
case (Cons x xs) with ‹Linear_order r› show ?case
unfolding order_on_defs
by (auto 4 4 simp: sorted_on_Cons sorted_on_many set_insort_on refl_on_def total_on_def elim: transE)
qed simp
lemma sorted_on_insort_on:
assumes "set (x # xs) ⊆ Field r"
shows "sorted_on r (insort_on r x xs) = sorted_on r xs"
using sorted_on_insort_key_on[where f="λx. x"] assms by simp
theorem sorted_on_sort_key_on [simp]:
assumes "f ` set xs ⊆ Field r"
shows "sorted_on r (map f (sort_key_on r f xs))"
using assms by (induct xs) (simp_all add: sorted_on_insort_key_on)
theorem sorted_on_sort_on [simp]:
assumes "set xs ⊆ Field r"
shows "sorted_on r (sort_on r xs)"
using sorted_on_sort_key_on[where f="λx. x"] assms by simp
lemma finite_sorted_on_distinct_unique:
assumes "A ⊆ Field r"
assumes "finite A"
shows "∃!xs. set xs = A ∧ sorted_on r xs ∧ distinct xs"
proof -
from ‹finite A› obtain xs where "set xs = A ∧ distinct xs"
using finite_distinct_list by blast
with ‹A ⊆ Field r› show ?thesis
by (fastforce intro!: ex1I[where a="sort_on r xs"] simp: sorted_on_distinct_set_unique)
qed
end
lemma sorted_on_linord_of_list_subseteq_r:
assumes "Linear_order r"
assumes "sorted_on r xs"
assumes "distinct xs"
shows "linord_of_list (rev xs) ⊆ r"
using assms
proof(induct xs)
case (Cons x xs)
then have "linord_of_list (rev xs) ⊆ r" by (simp add: sorted_on_Cons)
with Cons.prems show ?case
by (clarsimp simp: linord_of_list_append linord_of_list_singleton sorted_on_Cons)
(meson contra_subsetD subsetI underS_incl_iff)
qed simp
lemma sorted_on_linord_of_list:
assumes "Linear_order r"
assumes "set xs = Field r"
assumes "sorted_on r xs"
assumes "distinct xs"
shows "linord_of_list (rev xs) = r"
proof(rule equalityI)
from assms show "linord_of_list (rev xs) ⊆ r"
using sorted_on_linord_of_list_subseteq_r by blast
next
{ fix x y assume xy: "(x, y) ∈ r"
with ‹Linear_order r› have "(y, x) ∉ r - Id"
using Linear_order_in_diff_Id by (fastforce intro: FieldI1)
with linord_of_list_Linear_order[of "rev xs" "Field r"] assms xy
have "(x, y) ∈ linord_of_list (rev xs)"
by simp (metis Diff_subset FieldI1 FieldI2 Linear_order_in_diff_Id linord_of_list_Field set_rev sorted_on_linord_of_list_subseteq_r subset_eq) }
then show "r ⊆ linord_of_list (rev xs)" by clarsimp
qed
lemma linord_of_listP_rev:
assumes "z # zs ∈ set (subseqs xs)"
assumes "y ∈ set zs"
shows "linord_of_listP z y (rev xs)"
using assms by (induct xs) (auto simp: Let_def linord_of_listP_append dest: subseqs_set)
lemma linord_of_list_sorted_on_subseqs:
assumes "ys ∈ set (subseqs xs)"
assumes "distinct xs"
shows "sorted_on (linord_of_list (rev xs)) ys"
using assms
proof(induct ys)
case (Cons y ys) then show ?case
using linord_of_list_Linear_order[where xs="rev xs" and ys="Field (linord_of_list (rev xs))"]
by (force simp: Cons_in_subseqsD sorted_on_Cons linord_of_list_linord_of_listP linord_of_listP_rev dest: subseqs_set)
qed simp
lemma linord_of_list_sorted_on:
assumes "distinct xs"
shows "sorted_on (linord_of_list (rev xs)) xs"
by (rule linord_of_list_sorted_on_subseqs[OF subseqs_refl ‹distinct xs›])
lemma linear_order_on_list:
assumes "linear_order_on ys r"
assumes "ys = Field r"
assumes "finite ys"
shows "∃!xs. r = linord_of_list xs ∧ distinct xs ∧ set xs = ys"
using %invisible finite_sorted_on_distinct_unique[of r ys] sorted_on_linord_of_list[of r] assms
by simp (metis distinct_rev linord_of_list_sorted_on rev_rev_ident set_rev)
end