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,1110 +1,1096 @@ 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" begin type_synonym point = "int * int" subsection "Auxiliary Functions and Lemmas" 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 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 }" apply (induction xs) apply (auto) by (metis UnI1 UnI2 insert_iff)+ subsubsection \@{const length}\ fun t_length :: "'a list \ nat" where "t_length [] = 0" | "t_length (x#xs) = 1 + t_length xs" lemma t_length: "t_length xs = length xs" by (induction xs) auto 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 t_take :: "nat \ 'a list \ nat" where "t_take n [] = 0" | "t_take n (x#xs) = 1 + ( case n of 0 \ 0 | Suc m \ t_take m xs )" lemma t_take: "t_take n xs \ min (n + 1) (length xs)" by (induction xs arbitrary: n) (auto split: nat.split) subsubsection \@{const filter}\ fun t_filter :: "('a \ bool) \ 'a list \ nat" where "t_filter P [] = 0" | "t_filter P (x#xs) = 1 + (if P x then t_filter P xs else t_filter P xs)" lemma t_filter: "t_filter P xs = length xs" by (induction xs) auto 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 :: "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_take_drop_conv: "split_at n xs = (take n xs, drop n xs)" by (induction xs arbitrary: n) (auto split: nat.split) fun t_split_at :: "nat \ 'a list \ nat" where "t_split_at n [] = 0" | "t_split_at n (x#xs) = 1 + ( case n of 0 \ 0 | Suc m \ t_split_at m xs )" lemma t_split_at: "t_split_at n xs \ length xs" by (induction xs arbitrary: n) (auto split: nat.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" "(tsi, dsi) = split_at_it' acc n xs" shows "rev acc @ ts = tsi" and "ds = dsi" using assms apply (induction acc n xs arbitrary: ts rule: split_at_it'.induct) apply (auto simp: split_at.simps split: prod.splits nat.splits) done 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 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 :: "('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 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) function mergesort :: "('b \ 'a::linorder) \ 'b list \ 'b list" where "mergesort f [] = []" | "mergesort f [x] = [x]" | "mergesort f (x # y # xs') = ( let xs = x # y # xs' in let n = length xs div 2 in let (l, r) = split_at n xs in merge f (mergesort f l) (mergesort f r) )" by pat_completeness auto termination mergesort apply (relation "Wellfounded.measure (\(_, xs). length xs)") apply (auto simp: split_at_take_drop_conv Let_def) done 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" apply (induction f xs rule: mergesort.induct) apply (simp_all add: set_merge split_at_take_drop_conv) using set_take_drop by (metis list.simps(15)) 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" fun t_merge' :: "('b \ 'a::linorder) \ 'b list \ 'b list \ nat" where "t_merge' f (x#xs) (y#ys) = 1 + ( if f x \ f y then t_merge' f xs (y#ys) else t_merge' f (x#xs) ys )" | "t_merge' f xs [] = 0" | "t_merge' f [] ys = 0" definition t_merge :: "('b \ 'a::linorder) \ ('b list * 'b list) \ nat" where "t_merge f xys = t_merge' f (fst xys) (snd xys)" lemma t_merge: "t_merge f (xs, ys) \ length xs + length ys" unfolding t_merge_def by (induction f xs ys rule: t_merge'.induct) auto function t_mergesort :: "('b \ 'a::linorder) \ 'b list \ nat" where "t_mergesort f [] = 0" | "t_mergesort f [_] = 1" | "t_mergesort f (x # y # xs') = ( let xs = x # y # xs' in let (l, r) = split_at (length xs div 2) xs in t_length xs + t_split_at (length xs div 2) xs + t_mergesort f l + t_mergesort f r + t_merge f (l, r) )" by pat_completeness auto termination t_mergesort apply (relation "Wellfounded.measure (\(_, xs). length xs)") apply (auto simp: split_at_take_drop_conv Let_def) done function mergesort_recurrence :: "nat \ real" where "mergesort_recurrence 0 = 0" | "mergesort_recurrence 1 = 1" | "2 \ n \ mergesort_recurrence n = mergesort_recurrence (nat \real n / 2\) + mergesort_recurrence (nat \real n / 2\) + 3 * n" 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 t_mergesort_conv_mergesort_recurrence: "t_mergesort f xs \ mergesort_recurrence (length xs)" proof (induction f xs rule: t_mergesort.induct) case (2 f x) thus ?case using mergesort_recurrence.simps(2) by auto 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 note defs = XS_def N_def LR_def let ?LHS = "t_length XS + t_split_at (N div 2) XS + t_mergesort f L + t_mergesort f R + t_merge f (L, R)" let ?RHS = "mergesort_recurrence (nat \real N / 2\) + mergesort_recurrence (nat \real N / 2\) + 3 * N" have IHL: "t_mergesort f L \ mergesort_recurrence (length L)" using defs "3.IH"(1) prod.collapse by blast have IHR: "t_mergesort f R \ mergesort_recurrence (length R)" using defs "3.IH"(2) prod.collapse by blast 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: "t_mergesort f L \ mergesort_recurrence (nat \real N / 2\)" "t_mergesort f R \ mergesort_recurrence (nat \real N / 2\)" using IHL IHR by simp_all have "N = length L + length R" using * by linarith hence "t_merge f (L, R) \ N" using t_merge by simp moreover have "t_length XS = N" using t_length N_def by blast moreover have "t_split_at (N div 2) XS \ N" using t_split_at N_def by blast ultimately have *: "?LHS \ ?RHS" using IH by simp moreover have "t_mergesort f XS = ?LHS" using defs by (auto simp: Let_def split: prod.split) moreover have "mergesort_recurrence N = ?RHS" by (simp add: defs) ultimately have "t_mergesort f XS \ mergesort_recurrence N" by presburger thus ?case using XS_def N_def by blast qed auto theorem mergesort_recurrence: "mergesort_recurrence \ \(\n. n * ln n)" by (master_theorem) auto theorem t_mergesort_bigo: "t_mergesort f \ O[length going_to at_top]((\n. n * ln n) o length)" proof - have 0: "\xs. t_mergesort f xs \ (mergesort_recurrence o length) xs" unfolding comp_def using t_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 apply (auto simp: dist_commute sparse_def) by 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 :: "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_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 :: "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_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" fun t_find_closest_bf :: "point \ point list \ nat" where "t_find_closest_bf _ [] = 0" | "t_find_closest_bf _ [_] = 1" | "t_find_closest_bf p (p\<^sub>0 # ps) = 1 + ( let p\<^sub>1 = find_closest_bf p ps in t_find_closest_bf p ps + ( if dist p p\<^sub>0 < dist p p\<^sub>1 then 0 else 0 ) )" lemma t_find_closest_bf: "t_find_closest_bf p ps = length ps" by (induction p ps rule: t_find_closest_bf.induct) auto fun t_closest_pair_bf :: "point list \ nat" where "t_closest_pair_bf [] = 0" | "t_closest_pair_bf [_] = 1" | "t_closest_pair_bf [_, _] = 2" | "t_closest_pair_bf (p\<^sub>0 # ps) = 1 + ( let (c\<^sub>0, c\<^sub>1) = closest_pair_bf ps in t_closest_pair_bf ps + ( let p\<^sub>1 = find_closest_bf p\<^sub>0 ps in t_find_closest_bf p\<^sub>0 ps + ( if dist c\<^sub>0 c\<^sub>1 \ dist p\<^sub>0 p\<^sub>1 then 0 else 0 )) )" lemma t_closest_pair_bf: "t_closest_pair_bf ps \ length ps * length ps" proof (induction rule: t_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" have "t_closest_pair_bf ?ps \ length ?ps * length ?ps" using 4 prod_cases3 by metis thus ?case using "4.prems" t_find_closest_bf by simp qed auto 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: "\x \ S. \y \ S. x = y \ card S \ 1" by (metis One_nat_def card_infinite card_le_Suc0_iff_eq le_0_eq le_SucI) 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