diff --git a/thys/Closest_Pair_Points/Common.thy b/thys/Closest_Pair_Points/Common.thy --- a/thys/Closest_Pair_Points/Common.thy +++ b/thys/Closest_Pair_Points/Common.thy @@ -1,1229 +1,1215 @@ section "Common" theory Common imports "HOL-Library.Going_To_Filter" "Akra_Bazzi.Akra_Bazzi_Method" "Akra_Bazzi.Akra_Bazzi_Approximation" "HOL-Library.Code_Target_Numeral" "Root_Balanced_Tree.Time_Monad" begin type_synonym point = "int * int" subsection "Auxiliary Functions and Lemmas" subsubsection "Time Monad" lemma time_distrib_bind: "time (bind_tm tm f) = time tm + time (f (val tm))" unfolding bind_tm_def by (simp split: tm.split) lemmas time_simps = time_distrib_bind tick_def lemma bind_tm_cong[fundef_cong]: assumes "\v. v = val n \ f v = g v" "m = n" shows "bind_tm m f = bind_tm n g" using assms unfolding bind_tm_def by (auto split: tm.split) subsubsection "Landau Auxiliary" text \ The following lemma expresses a procedure for deriving complexity properties of the form @{prop"t \ O[m going_to at_top within A](f o m)"} where \<^item> \t\ is a (timing) function on same data domain (e.g. lists), \<^item> \m\ is a measure function on that data domain (e.g. length), \<^item> \t'\ is a function on @{typ nat}, \<^item> \A\ is the set of valid inputs for the data domain. One needs to show that \<^item> \t\ is bounded by @{term "t' o m"} for valid inputs \<^item> @{prop"t' \ O(f)"} to conclude the overall property @{prop"t \ O[m going_to at_top within A](f o m)"}. \ lemma bigo_measure_trans: fixes t :: "'a \ real" and t' :: "nat \ real" and m :: "'a \ nat" and f ::"nat \ real" assumes "\x. x \ A \ t x \ (t' o m) x" and "t' \ O(f)" and "\x. x \ A \ 0 \ t x" shows "t \ O[m going_to at_top within A](f o m)" proof - have 0: "\x. x \ A \ 0 \ (t' o m) x" by (meson assms(1,3) order_trans) have 1: "t \ O[m going_to at_top within A](t' o m)" apply(rule bigoI[where c=1]) using assms 0 by (simp add: eventually_inf_principal going_to_within_def) have 2: "t' o m \ O[m going_to at_top](f o m)" unfolding o_def going_to_def by(rule landau_o.big.filtercomap[OF assms(2)]) have 3: "t' o m \ O[m going_to at_top within A](f o m)" using landau_o.big.filter_mono[OF _2] going_to_mono[OF _subset_UNIV] by blast show ?thesis by(rule landau_o.big_trans[OF 1 3]) qed lemma const_1_bigo_n_ln_n: "(\(n::nat). 1) \ O(\n. n * ln n)" proof - have "\N. \(n::nat) \ N. (\x. 1 \ x * ln x) n" proof - have "\(n::nat) \ 3. (\x. 1 \ x * ln x) n" proof standard fix n show "3 \ n \ 1 \ real n * ln (real n)" proof standard assume "3 \ n" hence "1 \ real n" by simp moreover have "1 \ ln (real n)" using ln_ln_nonneg' \3 \ n\ by simp ultimately show "1 \ real n * ln (real n)" by (auto simp: order_trans) qed qed thus ?thesis by blast qed thus ?thesis by auto qed subsubsection "Miscellaneous Lemmas" lemma set_take_drop_i_le_j: "i \ j \ set xs = set (take j xs) \ set (drop i xs)" proof (induction xs arbitrary: i j) case (Cons x xs) show ?case proof (cases "i = 0") case True thus ?thesis using set_take_subset by force next case False hence "set xs = set (take (j - 1) xs) \ set (drop (i - 1) xs)" by (simp add: Cons diff_le_mono) moreover have "set (take j (x # xs)) = insert x (set (take (j - 1) xs))" using False Cons.prems by (auto simp: take_Cons') moreover have "set (drop i (x # xs)) = set (drop (i - 1) xs)" using False Cons.prems by (auto simp: drop_Cons') ultimately show ?thesis by auto qed qed simp lemma set_take_drop: "set xs = set (take n xs) \ set (drop n xs)" using set_take_drop_i_le_j by fast -lemma - assumes "sorted_wrt f xs" - shows sorted_wrt_take: "sorted_wrt f (take n xs)" - and sorted_wrt_drop: "sorted_wrt f (drop n xs)" -proof - - from assms have "sorted_wrt f (take n xs @ drop n xs)" by simp - then show "sorted_wrt f (take n xs)" and "sorted_wrt f (drop n xs)" - unfolding sorted_wrt_append by simp_all -qed - -lemma sorted_wrt_filter: - "sorted_wrt f xs \ sorted_wrt f (filter P xs)" - by (induction xs) auto - lemma sorted_wrt_take_drop: "sorted_wrt f xs \ \x \ set (take n xs). \y \ set (drop n xs). f x y" using sorted_wrt_append[of f "take n xs" "drop n xs"] by simp lemma sorted_wrt_hd_less: assumes "sorted_wrt f xs" "\x. f x x" shows "\x \ set xs. f (hd xs) x" using assms by (cases xs) auto lemma sorted_wrt_hd_less_take: assumes "sorted_wrt f (x # xs)" "\x. f x x" shows "\y \ set (take n (x # xs)). f x y" using assms sorted_wrt_hd_less in_set_takeD by fastforce lemma sorted_wrt_take_less_hd_drop: assumes "sorted_wrt f xs" "n < length xs" shows "\x \ set (take n xs). f x (hd (drop n xs))" using sorted_wrt_take_drop assms by fastforce lemma sorted_wrt_hd_drop_less_drop: assumes "sorted_wrt f xs" "\x. f x x" shows "\x \ set (drop n xs). f (hd (drop n xs)) x" using assms sorted_wrt_drop sorted_wrt_hd_less by blast lemma length_filter_P_impl_Q: "(\x. P x \ Q x) \ length (filter P xs) \ length (filter Q xs)" by (induction xs) auto lemma filter_Un: "set xs = A \ B \ set (filter P xs) = { x \ A. P x } \ { x \ B. P x }" by (induction xs) (auto, metis UnI1 insert_iff, metis UnI2 insert_iff) subsubsection \@{const length}\ fun length_tm :: "'a list \ nat tm" where "length_tm [] =1 return 0" | "length_tm (x # xs) =1 do { l <- length_tm xs; return (1 + l) }" lemma length_eq_val_length_tm: "val (length_tm xs) = length xs" by (induction xs) auto lemma time_length_tm: "time (length_tm xs) = length xs + 1" by (induction xs) (auto simp: time_simps) fun length_it' :: "nat \ 'a list \ nat" where "length_it' acc [] = acc" | "length_it' acc (x#xs) = length_it' (acc+1) xs" definition length_it :: "'a list \ nat" where "length_it xs = length_it' 0 xs" lemma length_conv_length_it': "length xs + acc = length_it' acc xs" by (induction acc xs rule: length_it'.induct) auto lemma length_conv_length_it[code_unfold]: "length xs = length_it xs" unfolding length_it_def using length_conv_length_it' add_0_right by metis subsubsection \@{const rev}\ fun rev_it' :: "'a list \ 'a list \ 'a list" where "rev_it' acc [] = acc" | "rev_it' acc (x#xs) = rev_it' (x#acc) xs" definition rev_it :: "'a list \ 'a list" where "rev_it xs = rev_it' [] xs" lemma rev_conv_rev_it': "rev xs @ acc = rev_it' acc xs" by (induction acc xs rule: rev_it'.induct) auto lemma rev_conv_rev_it[code_unfold]: "rev xs = rev_it xs" unfolding rev_it_def using rev_conv_rev_it' append_Nil2 by metis subsubsection \@{const take}\ fun take_tm :: "nat \ 'a list \ 'a list tm" where "take_tm n [] =1 return []" | "take_tm n (x # xs) =1 (case n of 0 \ return [] | Suc m \ do { ys <- take_tm m xs; return (x # ys) } )" lemma take_eq_val_take_tm: "val (take_tm n xs) = take n xs" by (induction xs arbitrary: n) (auto split: nat.split) lemma time_take_tm: "time (take_tm n xs) = min n (length xs) + 1" by (induction xs arbitrary: n) (auto simp: time_simps split: nat.split) subsubsection \@{const filter}\ fun filter_tm :: "('a \ bool) \ 'a list \ 'a list tm" where "filter_tm P [] =1 return []" | "filter_tm P (x # xs) =1 (if P x then do { ys <- filter_tm P xs; return (x # ys) } else filter_tm P xs )" lemma filter_eq_val_filter_tm: "val (filter_tm P xs) = filter P xs" by (induction xs) auto lemma time_filter_tm: "time (filter_tm P xs) = length xs + 1" by (induction xs) (auto simp: time_simps) fun filter_it' :: "'a list \ ('a \ bool) \ 'a list \ 'a list" where "filter_it' acc P [] = rev acc" | "filter_it' acc P (x#xs) = ( if P x then filter_it' (x#acc) P xs else filter_it' acc P xs )" definition filter_it :: "('a \ bool) \ 'a list \ 'a list" where "filter_it P xs = filter_it' [] P xs" lemma filter_conv_filter_it': "rev acc @ filter P xs = filter_it' acc P xs" by (induction acc P xs rule: filter_it'.induct) auto lemma filter_conv_filter_it[code_unfold]: "filter P xs = filter_it P xs" unfolding filter_it_def using filter_conv_filter_it' append_Nil rev.simps(1) by metis subsubsection \\split_at\\ fun split_at_tm :: "nat \ 'a list \ ('a list \ 'a list) tm" where "split_at_tm n [] =1 return ([], [])" | "split_at_tm n (x # xs) =1 ( case n of 0 \ return ([], x # xs) | Suc m \ do { (xs', ys') <- split_at_tm m xs; return (x # xs', ys') } )" fun split_at :: "nat \ 'a list \ 'a list \ 'a list" where "split_at n [] = ([], [])" | "split_at n (x # xs) = ( case n of 0 \ ([], x # xs) | Suc m \ let (xs', ys') = split_at m xs in (x # xs', ys') )" lemma split_at_eq_val_split_at_tm: "val (split_at_tm n xs) = split_at n xs" by (induction xs arbitrary: n) (auto split: nat.split prod.split) lemma split_at_take_drop_conv: "split_at n xs = (take n xs, drop n xs)" by (induction xs arbitrary: n) (auto simp: split: nat.split) lemma time_split_at_tm: "time (split_at_tm n xs) = min n (length xs) + 1" by (induction xs arbitrary: n) (auto simp: time_simps split: nat.split prod.split) fun split_at_it' :: "'a list \ nat \ 'a list \ ('a list * 'a list)" where "split_at_it' acc n [] = (rev acc, [])" | "split_at_it' acc n (x#xs) = ( case n of 0 \ (rev acc, x#xs) | Suc m \ split_at_it' (x#acc) m xs )" definition split_at_it :: "nat \ 'a list \ ('a list * 'a list)" where "split_at_it n xs = split_at_it' [] n xs" lemma split_at_conv_split_at_it': assumes "(ts, ds) = split_at n xs" "(ts', ds') = split_at_it' acc n xs" shows "rev acc @ ts = ts'" and "ds = ds'" using assms by (induction acc n xs arbitrary: ts rule: split_at_it'.induct) (auto simp: split: prod.splits nat.splits) lemma split_at_conv_split_at_it_prod: assumes "(ts, ds) = split_at n xs" "(ts', ds') = split_at_it n xs" shows "(ts, ds) = (ts', ds')" using assms unfolding split_at_it_def using split_at_conv_split_at_it' rev.simps(1) append_Nil by fast+ lemma split_at_conv_split_at_it[code_unfold]: "split_at n xs = split_at_it n xs" using split_at_conv_split_at_it_prod surj_pair by metis declare split_at_tm.simps [simp del] declare split_at.simps [simp del] subsection "Mergesort" subsubsection "Functional Correctness Proof" definition sorted_fst :: "point list \ bool" where "sorted_fst ps = sorted_wrt (\p\<^sub>0 p\<^sub>1. fst p\<^sub>0 \ fst p\<^sub>1) ps" definition sorted_snd :: "point list \ bool" where "sorted_snd ps = sorted_wrt (\p\<^sub>0 p\<^sub>1. snd p\<^sub>0 \ snd p\<^sub>1) ps" fun merge_tm :: "('b \ 'a::linorder) \ 'b list \ 'b list \ 'b list tm" where "merge_tm f (x # xs) (y # ys) =1 ( if f x \ f y then do { tl <- merge_tm f xs (y # ys); return (x # tl) } else do { tl <- merge_tm f (x # xs) ys; return (y # tl) } )" | "merge_tm f [] ys =1 return ys" | "merge_tm f xs [] =1 return xs" fun merge :: "('b \ 'a::linorder) \ 'b list \ 'b list \ 'b list" where "merge f (x # xs) (y # ys) = ( if f x \ f y then x # merge f xs (y # ys) else y # merge f (x # xs) ys )" | "merge f [] ys = ys" | "merge f xs [] = xs" lemma merge_eq_val_merge_tm: "val (merge_tm f xs ys) = merge f xs ys" by (induction f xs ys rule: merge.induct) auto lemma length_merge: "length (merge f xs ys) = length xs + length ys" by (induction f xs ys rule: merge.induct) auto lemma set_merge: "set (merge f xs ys) = set xs \ set ys" by (induction f xs ys rule: merge.induct) auto lemma distinct_merge: assumes "set xs \ set ys = {}" "distinct xs" "distinct ys" shows "distinct (merge f xs ys)" using assms by (induction f xs ys rule: merge.induct) (auto simp: set_merge) lemma sorted_merge: assumes "P = (\x y. f x \ f y)" shows "sorted_wrt P (merge f xs ys) \ sorted_wrt P xs \ sorted_wrt P ys" using assms by (induction f xs ys rule: merge.induct) (auto simp: set_merge) declare split_at_take_drop_conv [simp] function (sequential) mergesort_tm :: "('b \ 'a::linorder) \ 'b list \ 'b list tm" where "mergesort_tm f [] =1 return []" | "mergesort_tm f [x] =1 return [x]" | "mergesort_tm f xs =1 ( do { n <- length_tm xs; (xs\<^sub>l, xs\<^sub>r) <- split_at_tm (n div 2) xs; l <- mergesort_tm f xs\<^sub>l; r <- mergesort_tm f xs\<^sub>r; merge_tm f l r } )" by pat_completeness auto termination mergesort_tm by (relation "Wellfounded.measure (\(_, xs). length xs)") (auto simp add: length_eq_val_length_tm split_at_eq_val_split_at_tm) fun mergesort :: "('b \ 'a::linorder) \ 'b list \ 'b list" where "mergesort f [] = []" | "mergesort f [x] = [x]" | "mergesort f xs = ( let n = length xs div 2 in let (l, r) = split_at n xs in merge f (mergesort f l) (mergesort f r) )" declare split_at_take_drop_conv [simp del] lemma mergesort_eq_val_mergesort_tm: "val (mergesort_tm f xs) = mergesort f xs" by (induction f xs rule: mergesort.induct) (auto simp add: length_eq_val_length_tm split_at_eq_val_split_at_tm merge_eq_val_merge_tm split: prod.split) lemma sorted_wrt_mergesort: "sorted_wrt (\x y. f x \ f y) (mergesort f xs)" by (induction f xs rule: mergesort.induct) (auto simp: split_at_take_drop_conv sorted_merge) lemma set_mergesort: "set (mergesort f xs) = set xs" by (induction f xs rule: mergesort.induct) (simp_all add: set_merge split_at_take_drop_conv, metis list.simps(15) set_take_drop) lemma length_mergesort: "length (mergesort f xs) = length xs" by (induction f xs rule: mergesort.induct) (auto simp: length_merge split_at_take_drop_conv) lemma distinct_mergesort: "distinct xs \ distinct (mergesort f xs)" proof (induction f xs rule: mergesort.induct) case (3 f x y xs) let ?xs' = "x # y # xs" obtain l r where lr_def: "(l, r) = split_at (length ?xs' div 2) ?xs'" by (metis surj_pair) have "distinct l" "distinct r" using "3.prems" split_at_take_drop_conv distinct_take distinct_drop lr_def by (metis prod.sel)+ hence "distinct (mergesort f l)" "distinct (mergesort f r)" using "3.IH" lr_def by auto moreover have "set l \ set r = {}" using "3.prems" split_at_take_drop_conv lr_def by (metis append_take_drop_id distinct_append prod.sel) ultimately show ?case using lr_def by (auto simp: distinct_merge set_mergesort split: prod.splits) qed auto lemmas mergesort = sorted_wrt_mergesort set_mergesort length_mergesort distinct_mergesort lemma sorted_fst_take_less_hd_drop: assumes "sorted_fst ps" "n < length ps" shows "\p \ set (take n ps). fst p \ fst (hd (drop n ps))" using assms sorted_wrt_take_less_hd_drop[of "\p\<^sub>0 p\<^sub>1. fst p\<^sub>0 \ fst p\<^sub>1"] sorted_fst_def by fastforce lemma sorted_fst_hd_drop_less_drop: assumes "sorted_fst ps" shows "\p \ set (drop n ps). fst (hd (drop n ps)) \ fst p" using assms sorted_wrt_hd_drop_less_drop[of "\p\<^sub>0 p\<^sub>1. fst p\<^sub>0 \ fst p\<^sub>1"] sorted_fst_def by fastforce subsubsection "Time Complexity Proof" lemma time_merge_tm: "time (merge_tm f xs ys) \ length xs + length ys + 1" by (induction f xs ys rule: merge_tm.induct) (auto simp: time_simps) function mergesort_recurrence :: "nat \ real" where "mergesort_recurrence 0 = 1" | "mergesort_recurrence 1 = 1" | "2 \ n \ mergesort_recurrence n = 4 + 3 * n + mergesort_recurrence (nat \real n / 2\) + mergesort_recurrence (nat \real n / 2\)" by force simp_all termination by akra_bazzi_termination simp_all lemma mergesort_recurrence_nonneg[simp]: "0 \ mergesort_recurrence n" by (induction n rule: mergesort_recurrence.induct) (auto simp del: One_nat_def) lemma time_mergesort_conv_mergesort_recurrence: "time (mergesort_tm f xs) \ mergesort_recurrence (length xs)" proof (induction f xs rule: mergesort_tm.induct) case (1 f) thus ?case by (auto simp: time_simps) next case (2 f x) thus ?case using mergesort_recurrence.simps(2) by (auto simp: time_simps) next case (3 f x y xs') define xs where "xs = x # y # xs'" define n where "n = length xs" obtain l r where lr_def: "(l, r) = split_at (n div 2) xs" using prod.collapse by blast define l' where "l' = mergesort f l" define r' where "r' = mergesort f r" note defs = xs_def n_def lr_def l'_def r'_def have IHL: "time (mergesort_tm f l) \ mergesort_recurrence (length l)" using defs "3.IH"(1) by (auto simp: length_eq_val_length_tm split_at_eq_val_split_at_tm) have IHR: "time (mergesort_tm f r) \ mergesort_recurrence (length r)" using defs "3.IH"(2) by (auto simp: length_eq_val_length_tm split_at_eq_val_split_at_tm) have *: "length l = n div 2" "length r = n - n div 2" using defs by (auto simp: split_at_take_drop_conv) hence "(nat \real n / 2\) = length l" "(nat \real n / 2\) = length r" by linarith+ hence IH: "time (mergesort_tm f l) \ mergesort_recurrence (nat \real n / 2\)" "time (mergesort_tm f r) \ mergesort_recurrence (nat \real n / 2\)" using IHL IHR by simp_all have "n = length l + length r" using * by linarith hence "time (merge_tm f l' r') \ n + 1" using time_merge_tm defs by (metis length_mergesort) have "time (mergesort_tm f xs) = 1 + time (length_tm xs) + time (split_at_tm (n div 2) xs) + time (mergesort_tm f l) + time (mergesort_tm f r) + time (merge_tm f l' r')" using defs by (auto simp add: time_simps length_eq_val_length_tm mergesort_eq_val_mergesort_tm split_at_eq_val_split_at_tm split: prod.split) also have "... \ 4 + 3 * n + time (mergesort_tm f l) + time (mergesort_tm f r)" using time_length_tm[of xs] time_split_at_tm[of "n div 2" xs] n_def \time (merge_tm f l' r') \ n + 1\ by simp also have "... \ 4 + 3 * n + mergesort_recurrence (nat \real n / 2\) + mergesort_recurrence (nat \real n / 2\)" using IH by simp also have "... = mergesort_recurrence n" using defs by simp finally show ?case using defs by simp qed theorem mergesort_recurrence: "mergesort_recurrence \ \(\n. n * ln n)" by (master_theorem) auto theorem time_mergesort_tm_bigo: "(\xs. time (mergesort_tm f xs)) \ O[length going_to at_top]((\n. n * ln n) o length)" proof - have 0: "\xs. time (mergesort_tm f xs) \ (mergesort_recurrence o length) xs" unfolding comp_def using time_mergesort_conv_mergesort_recurrence by blast show ?thesis using bigo_measure_trans[OF 0] by (simp add: bigthetaD1 mergesort_recurrence) qed subsubsection "Code Export" lemma merge_xs_Nil[simp]: "merge f xs [] = xs" by (cases xs) auto fun merge_it' :: "('b \ 'a::linorder) \ 'b list \ 'b list \ 'b list \ 'b list" where "merge_it' f acc [] [] = rev acc" | "merge_it' f acc (x#xs) [] = merge_it' f (x#acc) xs []" | "merge_it' f acc [] (y#ys) = merge_it' f (y#acc) ys []" | "merge_it' f acc (x#xs) (y#ys) = ( if f x \ f y then merge_it' f (x#acc) xs (y#ys) else merge_it' f (y#acc) (x#xs) ys )" definition merge_it :: "('b \ 'a::linorder) \ 'b list \ 'b list \ 'b list" where "merge_it f xs ys = merge_it' f [] xs ys" lemma merge_conv_merge_it': "rev acc @ merge f xs ys = merge_it' f acc xs ys" by (induction f acc xs ys rule: merge_it'.induct) auto lemma merge_conv_merge_it[code_unfold]: "merge f xs ys = merge_it f xs ys" unfolding merge_it_def using merge_conv_merge_it' rev.simps(1) append_Nil by metis subsection "Minimal Distance" definition sparse :: "real \ point set \ bool" where "sparse \ ps \ (\p\<^sub>0 \ ps. \p\<^sub>1 \ ps. p\<^sub>0 \ p\<^sub>1 \ \ \ dist p\<^sub>0 p\<^sub>1)" lemma sparse_identity: assumes "sparse \ (set ps)" "\p \ set ps. \ \ dist p\<^sub>0 p" shows "sparse \ (set (p\<^sub>0 # ps))" using assms by (simp add: dist_commute sparse_def) lemma sparse_update: assumes "sparse \ (set ps)" assumes "dist p\<^sub>0 p\<^sub>1 \ \" "\p \ set ps. dist p\<^sub>0 p\<^sub>1 \ dist p\<^sub>0 p" shows "sparse (dist p\<^sub>0 p\<^sub>1) (set (p\<^sub>0 # ps))" using assms by (auto simp: dist_commute sparse_def, force+) lemma sparse_mono: "sparse \ P \ \ \ \ \ sparse \ P" unfolding sparse_def by fastforce subsection "Distance" lemma dist_transform: fixes p :: point and \ :: real and l :: int shows "dist p (l, snd p) < \ \ l - \ < fst p \ fst p < l + \" proof - have "dist p (l, snd p) = sqrt ((real_of_int (fst p) - l)\<^sup>2)" by (auto simp add: dist_prod_def dist_real_def prod.case_eq_if) thus ?thesis by auto qed fun dist_code :: "point \ point \ int" where "dist_code p\<^sub>0 p\<^sub>1 = (fst p\<^sub>0 - fst p\<^sub>1)\<^sup>2 + (snd p\<^sub>0 - snd p\<^sub>1)\<^sup>2" lemma dist_eq_sqrt_dist_code: fixes p\<^sub>0 :: point shows "dist p\<^sub>0 p\<^sub>1 = sqrt (dist_code p\<^sub>0 p\<^sub>1)" by (auto simp: dist_prod_def dist_real_def split: prod.splits) lemma dist_eq_dist_code_lt: fixes p\<^sub>0 :: point shows "dist p\<^sub>0 p\<^sub>1 < dist p\<^sub>2 p\<^sub>3 \ dist_code p\<^sub>0 p\<^sub>1 < dist_code p\<^sub>2 p\<^sub>3" using dist_eq_sqrt_dist_code real_sqrt_less_iff by presburger lemma dist_eq_dist_code_le: fixes p\<^sub>0 :: point shows "dist p\<^sub>0 p\<^sub>1 \ dist p\<^sub>2 p\<^sub>3 \ dist_code p\<^sub>0 p\<^sub>1 \ dist_code p\<^sub>2 p\<^sub>3" using dist_eq_sqrt_dist_code real_sqrt_le_iff by presburger lemma dist_eq_dist_code_abs_lt: fixes p\<^sub>0 :: point shows "\c\ < dist p\<^sub>0 p\<^sub>1 \ c\<^sup>2 < dist_code p\<^sub>0 p\<^sub>1" using dist_eq_sqrt_dist_code by (metis of_int_less_of_int_power_cancel_iff real_sqrt_abs real_sqrt_less_iff) lemma dist_eq_dist_code_abs_le: fixes p\<^sub>0 :: point shows "dist p\<^sub>0 p\<^sub>1 \ \c\ \ dist_code p\<^sub>0 p\<^sub>1 \ c\<^sup>2" using dist_eq_sqrt_dist_code by (metis of_int_power_le_of_int_cancel_iff real_sqrt_abs real_sqrt_le_iff) lemma dist_fst_abs: fixes p :: point and l :: int shows "dist p (l, snd p) = \fst p - l\" proof - have "dist p (l, snd p) = sqrt ((real_of_int (fst p) - l)\<^sup>2)" by (simp add: dist_prod_def dist_real_def prod.case_eq_if) thus ?thesis by simp qed declare dist_code.simps [simp del] subsection "Brute Force Closest Pair Algorithm" subsubsection "Functional Correctness Proof" fun find_closest_bf_tm :: "point \ point list \ point tm" where "find_closest_bf_tm _ [] =1 return undefined" | "find_closest_bf_tm _ [p] =1 return p" | "find_closest_bf_tm p (p\<^sub>0 # ps) =1 ( do { p\<^sub>1 <- find_closest_bf_tm p ps; if dist p p\<^sub>0 < dist p p\<^sub>1 then return p\<^sub>0 else return p\<^sub>1 } )" fun find_closest_bf :: "point \ point list \ point" where "find_closest_bf _ [] = undefined" | "find_closest_bf _ [p] = p" | "find_closest_bf p (p\<^sub>0 # ps) = ( let p\<^sub>1 = find_closest_bf p ps in if dist p p\<^sub>0 < dist p p\<^sub>1 then p\<^sub>0 else p\<^sub>1 )" lemma find_closest_bf_eq_val_find_closest_bf_tm: "val (find_closest_bf_tm p ps) = find_closest_bf p ps" by (induction p ps rule: find_closest_bf.induct) (auto simp: Let_def) lemma find_closest_bf_set: "0 < length ps \ find_closest_bf p ps \ set ps" by (induction p ps rule: find_closest_bf.induct) (auto simp: Let_def split: prod.splits if_splits) lemma find_closest_bf_dist: "\q \ set ps. dist p (find_closest_bf p ps) \ dist p q" by (induction p ps rule: find_closest_bf.induct) (auto split: prod.splits) fun closest_pair_bf_tm :: "point list \ (point \ point) tm" where "closest_pair_bf_tm [] =1 return undefined" | "closest_pair_bf_tm [_] =1 return undefined" | "closest_pair_bf_tm [p\<^sub>0, p\<^sub>1] =1 return (p\<^sub>0, p\<^sub>1)" | "closest_pair_bf_tm (p\<^sub>0 # ps) =1 ( do { (c\<^sub>0::point, c\<^sub>1::point) <- closest_pair_bf_tm ps; p\<^sub>1 <- find_closest_bf_tm p\<^sub>0 ps; if dist c\<^sub>0 c\<^sub>1 \ dist p\<^sub>0 p\<^sub>1 then return (c\<^sub>0, c\<^sub>1) else return (p\<^sub>0, p\<^sub>1) } )" fun closest_pair_bf :: "point list \ (point * point)" where "closest_pair_bf [] = undefined" | "closest_pair_bf [_] = undefined" | "closest_pair_bf [p\<^sub>0, p\<^sub>1] = (p\<^sub>0, p\<^sub>1)" | "closest_pair_bf (p\<^sub>0 # ps) = ( let (c\<^sub>0, c\<^sub>1) = closest_pair_bf ps in let p\<^sub>1 = find_closest_bf p\<^sub>0 ps in if dist c\<^sub>0 c\<^sub>1 \ dist p\<^sub>0 p\<^sub>1 then (c\<^sub>0, c\<^sub>1) else (p\<^sub>0, p\<^sub>1) )" lemma closest_pair_bf_eq_val_closest_pair_bf_tm: "val (closest_pair_bf_tm ps) = closest_pair_bf ps" by (induction ps rule: closest_pair_bf.induct) (auto simp: Let_def find_closest_bf_eq_val_find_closest_bf_tm split: prod.split) lemma closest_pair_bf_c0: "1 < length ps \ (c\<^sub>0, c\<^sub>1) = closest_pair_bf ps \ c\<^sub>0 \ set ps" by (induction ps arbitrary: c\<^sub>0 c\<^sub>1 rule: closest_pair_bf.induct) (auto simp: Let_def find_closest_bf_set split: if_splits prod.splits) lemma closest_pair_bf_c1: "1 < length ps \ (c\<^sub>0, c\<^sub>1) = closest_pair_bf ps \ c\<^sub>1 \ set ps" proof (induction ps arbitrary: c\<^sub>0 c\<^sub>1 rule: closest_pair_bf.induct) case (4 p\<^sub>0 p\<^sub>2 p\<^sub>3 ps) let ?ps = "p\<^sub>2 # p\<^sub>3 # ps" obtain c\<^sub>0 c\<^sub>1 where c\<^sub>0_def: "(c\<^sub>0, c\<^sub>1) = closest_pair_bf ?ps" using prod.collapse by blast define p\<^sub>1 where p\<^sub>1_def: "p\<^sub>1 = find_closest_bf p\<^sub>0 ?ps" note defs = c\<^sub>0_def p\<^sub>1_def have "c\<^sub>1 \ set ?ps" using "4.IH" defs by simp moreover have "p\<^sub>1 \ set ?ps" using find_closest_bf_set defs by blast ultimately show ?case using "4.prems"(2) defs by (auto simp: Let_def split: prod.splits if_splits) qed auto lemma closest_pair_bf_c0_ne_c1: "1 < length ps \ distinct ps \ (c\<^sub>0, c\<^sub>1) = closest_pair_bf ps \ c\<^sub>0 \ c\<^sub>1" proof (induction ps arbitrary: c\<^sub>0 c\<^sub>1 rule: closest_pair_bf.induct) case (4 p\<^sub>0 p\<^sub>2 p\<^sub>3 ps) let ?ps = "p\<^sub>2 # p\<^sub>3 # ps" obtain c\<^sub>0 c\<^sub>1 where c\<^sub>0_def: "(c\<^sub>0, c\<^sub>1) = closest_pair_bf ?ps" using prod.collapse by blast define p\<^sub>1 where p\<^sub>1_def: "p\<^sub>1 = find_closest_bf p\<^sub>0 ?ps" note defs = c\<^sub>0_def p\<^sub>1_def have "c\<^sub>0 \ c\<^sub>1" using "4.IH" "4.prems"(2) defs by simp moreover have "p\<^sub>0 \ p\<^sub>1" using find_closest_bf_set "4.prems"(2) defs by (metis distinct.simps(2) length_pos_if_in_set list.set_intros(1)) ultimately show ?case using "4.prems"(3) defs by (auto simp: Let_def split: prod.splits if_splits) qed auto lemmas closest_pair_bf_c0_c1 = closest_pair_bf_c0 closest_pair_bf_c1 closest_pair_bf_c0_ne_c1 lemma closest_pair_bf_dist: assumes "1 < length ps" "(c\<^sub>0, c\<^sub>1) = closest_pair_bf ps" shows "sparse (dist c\<^sub>0 c\<^sub>1) (set ps)" using assms proof (induction ps arbitrary: c\<^sub>0 c\<^sub>1 rule: closest_pair_bf.induct) case (4 p\<^sub>0 p\<^sub>2 p\<^sub>3 ps) let ?ps = "p\<^sub>2 # p\<^sub>3 # ps" obtain c\<^sub>0 c\<^sub>1 where c\<^sub>0_def: "(c\<^sub>0, c\<^sub>1) = closest_pair_bf ?ps" using prod.collapse by blast define p\<^sub>1 where p\<^sub>1_def: "p\<^sub>1 = find_closest_bf p\<^sub>0 ?ps" note defs = c\<^sub>0_def p\<^sub>1_def hence IH: "sparse (dist c\<^sub>0 c\<^sub>1) (set ?ps)" using 4 c\<^sub>0_def by simp have *: "\p \ set ?ps. (dist p\<^sub>0 p\<^sub>1) \ dist p\<^sub>0 p" using find_closest_bf_dist defs by blast show ?case proof (cases "dist c\<^sub>0 c\<^sub>1 \ dist p\<^sub>0 p\<^sub>1") case True hence "\p \ set ?ps. dist c\<^sub>0 c\<^sub>1 \ dist p\<^sub>0 p" using * by auto hence "sparse (dist c\<^sub>0 c\<^sub>1) (set (p\<^sub>0 # ?ps))" using sparse_identity IH by blast thus ?thesis using True "4.prems" defs by (auto split: prod.splits) next case False hence "sparse (dist p\<^sub>0 p\<^sub>1) (set (p\<^sub>0 # ?ps))" using sparse_update[of "dist c\<^sub>0 c\<^sub>1" ?ps p\<^sub>0 p\<^sub>1] IH * defs by argo thus ?thesis using False "4.prems" defs by (auto split: prod.splits) qed qed (auto simp: dist_commute sparse_def) subsubsection "Time Complexity Proof" lemma time_find_closest_bf_tm: "time (find_closest_bf_tm p ps) \ length ps + 1" by (induction p ps rule: find_closest_bf_tm.induct) (auto simp: time_simps) lemma time_closest_pair_bf_tm: "time (closest_pair_bf_tm ps) \ length ps * length ps + 1" proof (induction ps rule: closest_pair_bf_tm.induct) case (4 p\<^sub>0 p\<^sub>2 p\<^sub>3 ps) let ?ps = "p\<^sub>2 # p\<^sub>3 # ps" have "time (closest_pair_bf_tm (p\<^sub>0 # ?ps)) = 1 + time (find_closest_bf_tm p\<^sub>0 ?ps) + time (closest_pair_bf_tm ?ps)" by (auto simp: time_simps split: prod.split) also have "... \ 2 + length ?ps + time (closest_pair_bf_tm ?ps)" using time_find_closest_bf_tm[of p\<^sub>0 ?ps] by simp also have "... \ 2 + length ?ps + length ?ps * length ?ps + 1" using "4.IH" by simp also have "... \ length (p\<^sub>0 # ?ps) * length (p\<^sub>0 # ?ps) + 1" by auto finally show ?case by blast qed (auto simp: time_simps) subsubsection "Code Export" fun find_closest_bf_code :: "point \ point list \ (int * point)" where "find_closest_bf_code p [] = undefined" | "find_closest_bf_code p [p\<^sub>0] = (dist_code p p\<^sub>0, p\<^sub>0)" | "find_closest_bf_code p (p\<^sub>0 # ps) = ( let (\\<^sub>1, p\<^sub>1) = find_closest_bf_code p ps in let \\<^sub>0 = dist_code p p\<^sub>0 in if \\<^sub>0 < \\<^sub>1 then (\\<^sub>0, p\<^sub>0) else (\\<^sub>1, p\<^sub>1) )" lemma find_closest_bf_code_dist_eq: "0 < length ps \ (\, c) = find_closest_bf_code p ps \ \ = dist_code p c" by (induction p ps rule: find_closest_bf_code.induct) (auto simp: Let_def split: prod.splits if_splits) lemma find_closest_bf_code_eq: "0 < length ps \ c = find_closest_bf p ps \ (\', c') = find_closest_bf_code p ps \ c = c'" proof (induction p ps arbitrary: c \' c' rule: find_closest_bf.induct) case (3 p p\<^sub>0 p\<^sub>2 ps) define \\<^sub>0 \\<^sub>0' where \\<^sub>0_def: "\\<^sub>0 = dist p p\<^sub>0" "\\<^sub>0' = dist_code p p\<^sub>0" obtain \\<^sub>1 p\<^sub>1 \\<^sub>1' p\<^sub>1' where \\<^sub>1_def: "\\<^sub>1 = dist p p\<^sub>1" "p\<^sub>1 = find_closest_bf p (p\<^sub>2 # ps)" "(\\<^sub>1', p\<^sub>1') = find_closest_bf_code p (p\<^sub>2 # ps)" using prod.collapse by blast+ note defs = \\<^sub>0_def \\<^sub>1_def have *: "p\<^sub>1 = p\<^sub>1'" using "3.IH" defs by simp hence "\\<^sub>0 < \\<^sub>1 \ \\<^sub>0' < \\<^sub>1'" using find_closest_bf_code_dist_eq[of "p\<^sub>2 # ps" \\<^sub>1' p\<^sub>1' p] dist_eq_dist_code_lt defs by simp thus ?case using "3.prems"(2,3) * defs by (auto split: prod.splits) qed auto declare find_closest_bf_code.simps [simp del] fun closest_pair_bf_code :: "point list \ (int * point * point)" where "closest_pair_bf_code [] = undefined" | "closest_pair_bf_code [p\<^sub>0] = undefined" | "closest_pair_bf_code [p\<^sub>0, p\<^sub>1] = (dist_code p\<^sub>0 p\<^sub>1, p\<^sub>0, p\<^sub>1)" | "closest_pair_bf_code (p\<^sub>0 # ps) = ( let (\\<^sub>c, c\<^sub>0, c\<^sub>1) = closest_pair_bf_code ps in let (\\<^sub>p, p\<^sub>1) = find_closest_bf_code p\<^sub>0 ps in if \\<^sub>c \ \\<^sub>p then (\\<^sub>c, c\<^sub>0, c\<^sub>1) else (\\<^sub>p, p\<^sub>0, p\<^sub>1) )" lemma closest_pair_bf_code_dist_eq: "1 < length ps \ (\, c\<^sub>0, c\<^sub>1) = closest_pair_bf_code ps \ \ = dist_code c\<^sub>0 c\<^sub>1" proof (induction ps arbitrary: \ c\<^sub>0 c\<^sub>1 rule: closest_pair_bf_code.induct) case (4 p\<^sub>0 p\<^sub>2 p\<^sub>3 ps) let ?ps = "p\<^sub>2 # p\<^sub>3 # ps" obtain \\<^sub>c c\<^sub>0 c\<^sub>1 where \\<^sub>c_def: "(\\<^sub>c, c\<^sub>0, c\<^sub>1) = closest_pair_bf_code ?ps" by (metis prod_cases3) obtain \\<^sub>p p\<^sub>1 where \\<^sub>p_def: "(\\<^sub>p, p\<^sub>1) = find_closest_bf_code p\<^sub>0 ?ps" using prod.collapse by blast note defs = \\<^sub>c_def \\<^sub>p_def have "\\<^sub>c = dist_code c\<^sub>0 c\<^sub>1" using "4.IH" defs by simp moreover have "\\<^sub>p = dist_code p\<^sub>0 p\<^sub>1" using find_closest_bf_code_dist_eq defs by blast ultimately show ?case using "4.prems"(2) defs by (auto split: prod.splits if_splits) qed auto lemma closest_pair_bf_code_eq: assumes "1 < length ps" assumes "(c\<^sub>0, c\<^sub>1) = closest_pair_bf ps" "(\', c\<^sub>0', c\<^sub>1') = closest_pair_bf_code ps" shows "c\<^sub>0 = c\<^sub>0' \ c\<^sub>1 = c\<^sub>1'" using assms proof (induction ps arbitrary: c\<^sub>0 c\<^sub>1 \' c\<^sub>0' c\<^sub>1' rule: closest_pair_bf_code.induct) case (4 p\<^sub>0 p\<^sub>2 p\<^sub>3 ps) let ?ps = "p\<^sub>2 # p\<^sub>3 # ps" obtain c\<^sub>0 c\<^sub>1 \\<^sub>c' c\<^sub>0' c\<^sub>1' where \\<^sub>c_def: "(c\<^sub>0, c\<^sub>1) = closest_pair_bf ?ps" "(\\<^sub>c', c\<^sub>0', c\<^sub>1') = closest_pair_bf_code ?ps" by (metis prod_cases3) obtain p\<^sub>1 \\<^sub>p' p\<^sub>1' where \\<^sub>p_def: "p\<^sub>1 = find_closest_bf p\<^sub>0 ?ps" "(\\<^sub>p', p\<^sub>1') = find_closest_bf_code p\<^sub>0 ?ps" using prod.collapse by blast note defs = \\<^sub>c_def \\<^sub>p_def have A: "c\<^sub>0 = c\<^sub>0' \ c\<^sub>1 = c\<^sub>1'" using "4.IH" defs by simp moreover have B: "p\<^sub>1 = p\<^sub>1'" using find_closest_bf_code_eq defs by blast moreover have "\\<^sub>c' = dist_code c\<^sub>0' c\<^sub>1'" using defs closest_pair_bf_code_dist_eq[of ?ps] by simp moreover have "\\<^sub>p' = dist_code p\<^sub>0 p\<^sub>1'" using defs find_closest_bf_code_dist_eq by blast ultimately have "dist c\<^sub>0 c\<^sub>1 \ dist p\<^sub>0 p\<^sub>1 \ \\<^sub>c' \ \\<^sub>p'" by (simp add: dist_eq_dist_code_le) thus ?case using "4.prems"(2,3) defs A B by (auto simp: Let_def split: prod.splits) qed auto subsection "Geometry" subsubsection "Band Filter" lemma set_band_filter_aux: fixes \ :: real and ps :: "point list" assumes "p\<^sub>0 \ ps\<^sub>L" "p\<^sub>1 \ ps\<^sub>R" "p\<^sub>0 \ p\<^sub>1" "dist p\<^sub>0 p\<^sub>1 < \" "set ps = ps\<^sub>L \ ps\<^sub>R" assumes "\p \ ps\<^sub>L. fst p \ l" "\p \ ps\<^sub>R. l \ fst p" assumes "ps' = filter (\p. l - \ < fst p \ fst p < l + \) ps" shows "p\<^sub>0 \ set ps' \ p\<^sub>1 \ set ps'" proof (rule ccontr) assume "\ (p\<^sub>0 \ set ps' \ p\<^sub>1 \ set ps')" then consider (A) "p\<^sub>0 \ set ps' \ p\<^sub>1 \ set ps'" | (B) "p\<^sub>0 \ set ps' \ p\<^sub>1 \ set ps'" | (C) "p\<^sub>0 \ set ps' \ p\<^sub>1 \ set ps'" by blast thus False proof cases case A hence "fst p\<^sub>0 \ l - \ \ l + \ \ fst p\<^sub>0" "fst p\<^sub>1 \ l - \ \ l + \ \ fst p\<^sub>1" using assms(1,2,5,8) by auto hence "fst p\<^sub>0 \ l - \" "l + \ \ fst p\<^sub>1" using assms(1,2,6,7) by force+ hence "\ \ dist (fst p\<^sub>0) (fst p\<^sub>1)" using dist_real_def by simp hence "\ \ dist p\<^sub>0 p\<^sub>1" using dist_fst_le[of p\<^sub>0 p\<^sub>1] by (auto split: prod.splits) then show ?thesis using assms(4) by fastforce next case B hence "fst p\<^sub>1 \ l - \ \ l + \ \ fst p\<^sub>1" using assms(2,5,8) by auto hence "l + \ \ fst p\<^sub>1" using assms(2,7) by auto moreover have "fst p\<^sub>0 \ l" using assms(1,6) by simp ultimately have "\ \ dist (fst p\<^sub>0) (fst p\<^sub>1)" using dist_real_def by simp hence "\ \ dist p\<^sub>0 p\<^sub>1" using dist_fst_le[of p\<^sub>0 p\<^sub>1] less_le_trans by (auto split: prod.splits) thus ?thesis using assms(4) by simp next case C hence "fst p\<^sub>0 \ l - \ \ l + \ \ fst p\<^sub>0" using assms(1,2,5,8) by auto hence "fst p\<^sub>0 \ l - \" using assms(1,6) by auto moreover have "l \ fst p\<^sub>1" using assms(2,7) by simp ultimately have "\ \ dist (fst p\<^sub>0) (fst p\<^sub>1)" using dist_real_def by simp hence "\ \ dist p\<^sub>0 p\<^sub>1" using dist_fst_le[of p\<^sub>0 p\<^sub>1] less_le_trans by (auto split: prod.splits) thus ?thesis using assms(4) by simp qed qed lemma set_band_filter: fixes \ :: real and ps :: "point list" assumes "p\<^sub>0 \ set ps" "p\<^sub>1 \ set ps" "p\<^sub>0 \ p\<^sub>1" "dist p\<^sub>0 p\<^sub>1 < \" "set ps = ps\<^sub>L \ ps\<^sub>R" assumes "sparse \ ps\<^sub>L" "sparse \ ps\<^sub>R" assumes "\p \ ps\<^sub>L. fst p \ l" "\p \ ps\<^sub>R. l \ fst p" assumes "ps' = filter (\p. l - \ < fst p \ fst p < l + \) ps" shows "p\<^sub>0 \ set ps' \ p\<^sub>1 \ set ps'" proof - have "p\<^sub>0 \ ps\<^sub>L \ p\<^sub>1 \ ps\<^sub>L" "p\<^sub>0 \ ps\<^sub>R \ p\<^sub>1 \ ps\<^sub>R" using assms(3,4,6,7) sparse_def by force+ then consider (A) "p\<^sub>0 \ ps\<^sub>L \ p\<^sub>1 \ ps\<^sub>R" | (B) "p\<^sub>0 \ ps\<^sub>R \ p\<^sub>1 \ ps\<^sub>L" using assms(1,2,5) by auto thus ?thesis proof cases case A thus ?thesis using set_band_filter_aux assms(3,4,5,8,9,10) by (auto split: prod.splits) next case B moreover have "dist p\<^sub>1 p\<^sub>0 < \" using assms(4) dist_commute by metis ultimately show ?thesis using set_band_filter_aux assms(3)[symmetric] assms(5,8,9,10) by (auto split: prod.splits) qed qed subsubsection "2D-Boxes and Points" lemma cbox_2D: fixes x\<^sub>0 :: real and y\<^sub>0 :: real shows "cbox (x\<^sub>0, y\<^sub>0) (x\<^sub>1, y\<^sub>1) = { (x, y). x\<^sub>0 \ x \ x \ x\<^sub>1 \ y\<^sub>0 \ y \ y \ y\<^sub>1 }" by fastforce lemma mem_cbox_2D: fixes x :: real and y :: real shows "x\<^sub>0 \ x \ x \ x\<^sub>1 \ y\<^sub>0 \ y \ y \ y\<^sub>1 \ (x, y) \ cbox (x\<^sub>0, y\<^sub>0) (x\<^sub>1, y\<^sub>1)" by fastforce lemma cbox_top_un: fixes x\<^sub>0 :: real and y\<^sub>0 :: real assumes "y\<^sub>0 \ y\<^sub>1" "y\<^sub>1 \ y\<^sub>2" shows "cbox (x\<^sub>0, y\<^sub>0) (x\<^sub>1, y\<^sub>1) \ cbox (x\<^sub>0, y\<^sub>1) (x\<^sub>1, y\<^sub>2) = cbox (x\<^sub>0, y\<^sub>0) (x\<^sub>1, y\<^sub>2)" using assms by auto lemma cbox_right_un: fixes x\<^sub>0 :: real and y\<^sub>0 :: real assumes "x\<^sub>0 \ x\<^sub>1" "x\<^sub>1 \ x\<^sub>2" shows "cbox (x\<^sub>0, y\<^sub>0) (x\<^sub>1, y\<^sub>1) \ cbox (x\<^sub>1, y\<^sub>0) (x\<^sub>2, y\<^sub>1) = cbox (x\<^sub>0, y\<^sub>0) (x\<^sub>2, y\<^sub>1)" using assms by auto lemma cbox_max_dist: assumes "p\<^sub>0 = (x, y)" "p\<^sub>1 = (x + \, y + \)" assumes "(x\<^sub>0, y\<^sub>0) \ cbox p\<^sub>0 p\<^sub>1" "(x\<^sub>1, y\<^sub>1) \ cbox p\<^sub>0 p\<^sub>1" "0 \ \" shows "dist (x\<^sub>0, y\<^sub>0) (x\<^sub>1, y\<^sub>1) \ sqrt 2 * \" proof - have X: "dist x\<^sub>0 x\<^sub>1 \ \" using assms dist_real_def by auto have Y: "dist y\<^sub>0 y\<^sub>1 \ \" using assms dist_real_def by auto have "dist (x\<^sub>0, y\<^sub>0) (x\<^sub>1, y\<^sub>1) = sqrt ((dist x\<^sub>0 x\<^sub>1)\<^sup>2 + (dist y\<^sub>0 y\<^sub>1)\<^sup>2)" using dist_Pair_Pair by auto also have "... \ sqrt (\\<^sup>2 + (dist y\<^sub>0 y\<^sub>1)\<^sup>2)" using X power_mono by fastforce also have "... \ sqrt (\\<^sup>2 + \\<^sup>2)" using Y power_mono by fastforce also have "... = sqrt 2 * sqrt (\\<^sup>2)" using real_sqrt_mult by simp also have "... = sqrt 2 * \" using assms(5) by simp finally show ?thesis . qed subsubsection "Pigeonhole Argument" lemma card_le_1_if_pairwise_eq: assumes "\x \ S. \y \ S. x = y" shows "card S \ 1" proof (rule ccontr) assume "\ card S \ 1" hence "2 \ card S" by simp then obtain T where *: "T \ S \ card T = 2" using ex_card by metis then obtain x y where "x \ T \ y \ T \ x \ y" by (meson card_2_iff') then show False using * assms by blast qed lemma card_Int_if_either_in: assumes "\x \ S. \y \ S. x = y \ x \ T \ y \ T" shows "card (S \ T) \ 1" proof (rule ccontr) assume "\ (card (S \ T) \ 1)" then obtain x y where *: "x \ S \ T \ y \ S \ T \ x \ y" by (meson card_le_1_if_pairwise_eq) hence "x \ T" "y \ T" by simp_all moreover have "x \ T \ y \ T" using assms * by auto ultimately show False by blast qed lemma card_Int_Un_le_Sum_card_Int: assumes "finite S" shows "card (A \ \S) \ (\B \ S. card (A \ B))" using assms proof (induction "card S" arbitrary: S) case (Suc n) then obtain B T where *: "S = { B } \ T" "card T = n" "B \ T" by (metis card_Suc_eq Suc_eq_plus1 insert_is_Un) hence "card (A \ \S) = card (A \ \({ B } \ T))" by blast also have "... \ card (A \ B) + card (A \ \T)" by (simp add: card_Un_le inf_sup_distrib1) also have "... \ card (A \ B) + (\B \ T. card (A \ B))" using Suc * by simp also have "... \ (\B \ S. card (A \ B))" using Suc.prems * by simp finally show ?case . qed simp lemma pigeonhole: assumes "finite T" "S \ \T" "card T < card S" shows "\x \ S. \y \ S. \X \ T. x \ y \ x \ X \ y \ X" proof (rule ccontr) assume "\ (\x \ S. \y \ S. \X \ T. x \ y \ x \ X \ y \ X)" hence *: "\X \ T. card (S \ X) \ 1" using card_Int_if_either_in by metis have "card T < card (S \ \T)" using Int_absorb2 assms by fastforce also have "... \ (\X \ T. card (S \ X))" using assms(1) card_Int_Un_le_Sum_card_Int by blast also have "... \ card T" using * sum_mono by fastforce finally show False by simp qed subsubsection "Delta Sparse Points within a Square" lemma max_points_square: assumes "\p \ ps. p \ cbox (x, y) (x + \, y + \)" "sparse \ ps" "0 \ \" shows "card ps \ 4" proof (cases "\ = 0") case True hence "{ (x, y) } = cbox (x, y) (x + \, y + \)" using cbox_def by simp hence "\p \ ps. p = (x, y)" using assms(1) by blast hence "\p \ ps. \q \ ps. p = q" apply (auto split: prod.splits) by (metis of_int_eq_iff)+ thus ?thesis using card_le_1_if_pairwise_eq by force next case False hence \: "0 < \" using assms(3) by simp show ?thesis proof (rule ccontr) assume A: "\ (card ps \ 4)" define PS where PS_def: "PS = (\(x, y). (real_of_int x, real_of_int y)) ` ps" have "inj_on (\(x, y). (real_of_int x, real_of_int y)) ps" using inj_on_def by fastforce hence *: "\ (card PS \ 4)" using A PS_def by (simp add: card_image) let ?x' = "x + \ / 2" let ?y' = "y + \ / 2" let ?ll = "cbox ( x , y ) (?x' , ?y' )" let ?lu = "cbox ( x , ?y') (?x' , y + \)" let ?rl = "cbox (?x', y ) ( x + \, ?y' )" let ?ru = "cbox (?x', ?y') ( x + \, y + \)" let ?sq = "{ ?ll, ?lu, ?rl, ?ru }" have card_le_4: "card ?sq \ 4" by (simp add: card_insert_le_m1) have "cbox (x, y) (?x', y + \) = ?ll \ ?lu" using cbox_top_un assms(3) by auto moreover have "cbox (?x', y) (x + \, y + \) = ?rl \ ?ru" using cbox_top_un assms(3) by auto moreover have "cbox (x, y) (?x', y + \) \ cbox (?x', y) (x + \, y + \) = cbox (x, y) (x + \, y + \)" using cbox_right_un assms(3) by simp ultimately have "?ll \ ?lu \ ?rl \ ?ru = cbox (x, y) (x + \, y + \)" by blast hence "PS \ \(?sq)" using assms(1) PS_def by (auto split: prod.splits) moreover have "card ?sq < card PS" using * card_insert_le_m1 card_le_4 by linarith moreover have "finite ?sq" by simp ultimately have "\p\<^sub>0 \ PS. \p\<^sub>1 \ PS. \S \ ?sq. (p\<^sub>0 \ p\<^sub>1 \ p\<^sub>0 \ S \ p\<^sub>1 \ S)" using pigeonhole[of ?sq PS] by blast then obtain S p\<^sub>0 p\<^sub>1 where #: "p\<^sub>0 \ PS" "p\<^sub>1 \ PS" "S \ ?sq" "p\<^sub>0 \ p\<^sub>1" "p\<^sub>0 \ S" "p\<^sub>1 \ S" by blast have D: "0 \ \ / 2" using assms(3) by simp have LL: "\p\<^sub>0 \ ?ll. \p\<^sub>1 \ ?ll. dist p\<^sub>0 p\<^sub>1 \ sqrt 2 * (\ / 2)" using cbox_max_dist[of "(x, y)" x y "(?x', ?y')" "\ / 2"] D by auto have LU: "\p\<^sub>0 \ ?lu. \p\<^sub>1 \ ?lu. dist p\<^sub>0 p\<^sub>1 \ sqrt 2 * (\ / 2)" using cbox_max_dist[of "(x, ?y')" x ?y' "(?x', y + \)" "\ / 2"] D by auto have RL: "\p\<^sub>0 \ ?rl. \p\<^sub>1 \ ?rl. dist p\<^sub>0 p\<^sub>1 \ sqrt 2 * (\ / 2)" using cbox_max_dist[of "(?x', y)" ?x' y "(x + \, ?y')" "\ / 2"] D by auto have RU: "\p\<^sub>0 \ ?ru. \p\<^sub>1 \ ?ru. dist p\<^sub>0 p\<^sub>1 \ sqrt 2 * (\ / 2)" using cbox_max_dist[of "(?x', ?y')" ?x' ?y' "(x + \, y + \)" "\ / 2"] D by auto have "\p\<^sub>0 \ S. \p\<^sub>1 \ S. dist p\<^sub>0 p\<^sub>1 \ sqrt 2 * (\ / 2)" using # LL LU RL RU by blast hence "dist p\<^sub>0 p\<^sub>1 \ (sqrt 2 / 2) * \" using # by simp moreover have "(sqrt 2 / 2) * \ < \" using sqrt2_less_2 \ by simp ultimately have "dist p\<^sub>0 p\<^sub>1 < \" by simp moreover have "\ \ dist p\<^sub>0 p\<^sub>1" using assms(2) # sparse_def PS_def by auto ultimately show False by simp qed qed end \ No newline at end of file