632 | "T_partition3 x (y # ys) = T_partition3 x ys + 1" |
632 | "T_partition3 x (y # ys) = T_partition3 x ys + 1" |
633 |
633 |
634 lemma T_partition3_eq: "T_partition3 x xs = length xs + 1" |
634 lemma T_partition3_eq: "T_partition3 x xs = length xs + 1" |
635 by (induction x xs rule: T_partition3.induct) auto |
635 by (induction x xs rule: T_partition3.induct) auto |
636 |
636 |
637 definition T_slow_select :: "nat \<Rightarrow> 'a :: linorder list \<Rightarrow> nat" where |
637 |
638 "T_slow_select k xs = T_insort xs + T_nth (insort xs) k + 1" |
638 time_definition slow_select |
|
639 |
|
640 lemmas T_slow_select_def [simp del] = T_slow_select.simps |
|
641 |
639 |
642 |
640 definition T_slow_median :: "'a :: linorder list \<Rightarrow> nat" where |
643 definition T_slow_median :: "'a :: linorder list \<Rightarrow> nat" where |
641 "T_slow_median xs = T_slow_select ((length xs - 1) div 2) xs + 1" |
644 "T_slow_median xs = T_length xs + T_slow_select ((length xs - 1) div 2) xs" |
642 |
645 |
643 lemma T_slow_select_le: "T_slow_select k xs \<le> length xs ^ 2 + 3 * length xs + 3" |
646 lemma T_slow_select_le: "T_slow_select k xs \<le> length xs ^ 2 + 3 * length xs + 2" |
644 proof - |
647 proof - |
645 have "T_slow_select k xs \<le> (length xs + 1)\<^sup>2 + (length (insort xs) + 1) + 1" |
648 have "T_slow_select k xs \<le> (length xs + 1)\<^sup>2 + (length (insort xs) + 1)" |
646 unfolding T_slow_select_def |
649 unfolding T_slow_select_def |
647 by (intro add_mono T_insort_length) (auto simp: T_nth_eq) |
650 by (intro add_mono T_insort_length) (auto simp: T_nth_eq) |
648 also have "\<dots> = length xs ^ 2 + 3 * length xs + 3" |
651 also have "\<dots> = length xs ^ 2 + 3 * length xs + 2" |
649 by (simp add: insort_correct algebra_simps power2_eq_square) |
652 by (simp add: insort_correct algebra_simps power2_eq_square) |
650 finally show ?thesis . |
653 finally show ?thesis . |
651 qed |
654 qed |
652 |
655 |
653 lemma T_slow_median_le: "T_slow_median xs \<le> length xs ^ 2 + 3 * length xs + 4" |
656 lemma T_slow_median_le: "T_slow_median xs \<le> length xs ^ 2 + 4 * length xs + 3" |
654 unfolding T_slow_median_def using T_slow_select_le[of "(length xs - 1) div 2" xs] by simp |
657 unfolding T_slow_median_def using T_slow_select_le[of "(length xs - 1) div 2" xs] |
655 |
658 by (simp add: algebra_simps T_length_eq) |
656 |
659 |
657 fun T_chop :: "nat \<Rightarrow> 'a list \<Rightarrow> nat" where |
660 |
658 "T_chop 0 _ = 1" |
661 time_fun chop |
659 | "T_chop _ [] = 1" |
|
660 | "T_chop n xs = T_take n xs + T_drop n xs + T_chop n (drop n xs)" |
|
661 |
662 |
662 lemmas [simp del] = T_chop.simps |
663 lemmas [simp del] = T_chop.simps |
663 |
664 |
664 lemma T_chop_Nil [simp]: "T_chop d [] = 1" |
665 lemma T_chop_Nil [simp]: "T_chop d [] = 1" |
665 by (cases d) (auto simp: T_chop.simps) |
666 by (cases d) (auto simp: T_chop.simps) |
666 |
667 |
667 lemma T_chop_0 [simp]: "T_chop 0 xs = 1" |
668 lemma T_chop_0 [simp]: "T_chop 0 xs = 1" |
668 by (auto simp: T_chop.simps) |
669 by (auto simp: T_chop.simps) |
669 |
670 |
670 lemma T_chop_reduce: |
671 lemma T_chop_reduce: |
671 "n > 0 \<Longrightarrow> xs \<noteq> [] \<Longrightarrow> T_chop n xs = T_take n xs + T_drop n xs + T_chop n (drop n xs)" |
672 "n > 0 \<Longrightarrow> xs \<noteq> [] \<Longrightarrow> T_chop n xs = T_take n xs + T_drop n xs + T_chop n (drop n xs) + 1" |
672 by (cases n; cases xs) (auto simp: T_chop.simps) |
673 by (cases n; cases xs) (auto simp: T_chop.simps) |
673 |
674 |
674 lemma T_chop_le: "T_chop d xs \<le> 5 * length xs + 1" |
675 lemma T_chop_le: "T_chop d xs \<le> 5 * length xs + 1" |
675 by (induction d xs rule: T_chop.induct) (auto simp: T_chop_reduce T_take_eq T_drop_eq) |
676 by (induction d xs rule: T_chop.induct) (auto simp: T_chop_reduce T_take_eq T_drop_eq) |
|
677 |
676 |
678 |
677 text \<open> |
679 text \<open> |
678 The option \<open>domintros\<close> here allows us to explicitly reason about where the function does and |
680 The option \<open>domintros\<close> here allows us to explicitly reason about where the function does and |
679 does not terminate. With this, we can skip the termination proof this time because we can |
681 does not terminate. With this, we can skip the termination proof this time because we can |
680 reuse the one for \<^const>\<open>mom_select\<close>. |
682 reuse the one for \<^const>\<open>mom_select\<close>. |
681 \<close> |
683 \<close> |
682 function (domintros) T_mom_select :: "nat \<Rightarrow> 'a :: linorder list \<Rightarrow> nat" where |
684 function (domintros) T_mom_select :: "nat \<Rightarrow> 'a :: linorder list \<Rightarrow> nat" where |
683 "T_mom_select k xs = ( |
685 "T_mom_select k xs = T_length xs + ( |
684 if length xs \<le> 20 then |
686 if length xs \<le> 20 then |
685 T_slow_select k xs |
687 T_slow_select k xs |
686 else |
688 else |
687 let xss = chop 5 xs; |
689 let xss = chop 5 xs; |
688 ms = map slow_median xss; |
690 ms = map slow_median xss; |
691 (ls, es, gs) = partition3 x xs; |
693 (ls, es, gs) = partition3 x xs; |
692 nl = length ls; |
694 nl = length ls; |
693 ne = length es |
695 ne = length es |
694 in |
696 in |
695 (if k < nl then T_mom_select k ls |
697 (if k < nl then T_mom_select k ls |
696 else if k < nl + ne then 0 |
698 else T_length es + (if k < nl + ne then 0 else T_mom_select (k - nl - ne) gs)) + |
697 else T_mom_select (k - nl - ne) gs) + |
|
698 T_mom_select idx ms + T_chop 5 xs + T_map T_slow_median xss + |
699 T_mom_select idx ms + T_chop 5 xs + T_map T_slow_median xss + |
699 T_partition3 x xs + T_length ls + T_length es + 1 |
700 T_partition3 x xs + T_length ls + 1 |
700 )" |
701 )" |
701 by auto |
702 by auto |
702 |
703 |
703 termination T_mom_select |
704 termination T_mom_select |
704 proof (rule allI, safe) |
705 proof (rule allI, safe) |
714 |
715 |
715 |
716 |
716 function T'_mom_select :: "nat \<Rightarrow> nat" where |
717 function T'_mom_select :: "nat \<Rightarrow> nat" where |
717 "T'_mom_select n = |
718 "T'_mom_select n = |
718 (if n \<le> 20 then |
719 (if n \<le> 20 then |
719 463 |
720 483 |
720 else |
721 else |
721 T'_mom_select (nat \<lceil>0.2*n\<rceil>) + T'_mom_select (nat \<lceil>0.7*n+3\<rceil>) + 17 * n + 50)" |
722 T'_mom_select (nat \<lceil>0.2*n\<rceil>) + T'_mom_select (nat \<lceil>0.7*n+3\<rceil>) + 19 * n + 55)" |
722 by force+ |
723 by force+ |
723 termination by (relation "measure id"; simp; linarith) |
724 termination by (relation "measure id"; simp; linarith) |
724 |
725 |
725 lemmas [simp del] = T'_mom_select.simps |
726 lemmas [simp del] = T'_mom_select.simps |
726 |
727 |
727 |
728 |
728 lemma T'_mom_select_ge: "T'_mom_select n \<ge> 463" |
729 lemma T'_mom_select_ge: "T'_mom_select n \<ge> 483" |
729 by (induction n rule: T'_mom_select.induct; subst T'_mom_select.simps) auto |
730 by (induction n rule: T'_mom_select.induct; subst T'_mom_select.simps) auto |
730 |
731 |
731 lemma T'_mom_select_mono: |
732 lemma T'_mom_select_mono: |
732 "m \<le> n \<Longrightarrow> T'_mom_select m \<le> T'_mom_select n" |
733 "m \<le> n \<Longrightarrow> T'_mom_select m \<le> T'_mom_select n" |
733 proof (induction n arbitrary: m rule: less_induct) |
734 proof (induction n arbitrary: m rule: less_induct) |
734 case (less n m) |
735 case (less n m) |
735 show ?case |
736 show ?case |
736 proof (cases "m \<le> 20") |
737 proof (cases "m \<le> 20") |
737 case True |
738 case True |
738 hence "T'_mom_select m = 463" |
739 hence "T'_mom_select m = 483" |
739 by (subst T'_mom_select.simps) auto |
740 by (subst T'_mom_select.simps) auto |
740 also have "\<dots> \<le> T'_mom_select n" |
741 also have "\<dots> \<le> T'_mom_select n" |
741 by (rule T'_mom_select_ge) |
742 by (rule T'_mom_select_ge) |
742 finally show ?thesis . |
743 finally show ?thesis . |
743 next |
744 next |
744 case False |
745 case False |
745 hence "T'_mom_select m = |
746 hence "T'_mom_select m = |
746 T'_mom_select (nat \<lceil>0.2*m\<rceil>) + T'_mom_select (nat \<lceil>0.7*m + 3\<rceil>) + 17 * m + 50" |
747 T'_mom_select (nat \<lceil>0.2*m\<rceil>) + T'_mom_select (nat \<lceil>0.7*m + 3\<rceil>) + 19 * m + 55" |
747 by (subst T'_mom_select.simps) auto |
748 by (subst T'_mom_select.simps) auto |
748 also have "\<dots> \<le> T'_mom_select (nat \<lceil>0.2*n\<rceil>) + T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>) + 17 * n + 50" |
749 also have "\<dots> \<le> T'_mom_select (nat \<lceil>0.2*n\<rceil>) + T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>) + 19 * n + 55" |
749 using \<open>m \<le> n\<close> and False by (intro add_mono less.IH; linarith) |
750 using \<open>m \<le> n\<close> and False by (intro add_mono less.IH; linarith) |
750 also have "\<dots> = T'_mom_select n" |
751 also have "\<dots> = T'_mom_select n" |
751 using \<open>m \<le> n\<close> and False by (subst T'_mom_select.simps) auto |
752 using \<open>m \<le> n\<close> and False by (subst T'_mom_select.simps) auto |
752 finally show ?thesis . |
753 finally show ?thesis . |
753 qed |
754 qed |
768 note IH = "1.IH"(1,2,3)[OF _ refl refl refl x_def tw refl refl refl refl] |
769 note IH = "1.IH"(1,2,3)[OF _ refl refl refl x_def tw refl refl refl refl] |
769 |
770 |
770 show ?case |
771 show ?case |
771 proof (cases "length xs \<le> 20") |
772 proof (cases "length xs \<le> 20") |
772 case True \<comment> \<open>base case\<close> |
773 case True \<comment> \<open>base case\<close> |
773 hence "T_mom_select k xs \<le> (length xs)\<^sup>2 + 3 * length xs + 3" |
774 hence "T_mom_select k xs \<le> (length xs)\<^sup>2 + 4 * length xs + 3" |
774 using T_slow_select_le[of k xs] by (subst T_mom_select.simps) auto |
775 using T_slow_select_le[of k xs] by (subst T_mom_select.simps) (auto simp: T_length_eq) |
775 also have "\<dots> \<le> 20\<^sup>2 + 3 * 20 + 3" |
776 also have "\<dots> \<le> 20\<^sup>2 + 4 * 20 + 3" |
776 using True by (intro add_mono power_mono) auto |
777 using True by (intro add_mono power_mono) auto |
777 also have "\<dots> \<le> 463" |
778 also have "\<dots> = 483" |
778 by simp |
779 by simp |
779 also have "\<dots> = T'_mom_select (length xs)" |
780 also have "\<dots> = T'_mom_select (length xs)" |
780 using True by (simp add: T'_mom_select.simps) |
781 using True by (simp add: T'_mom_select.simps) |
781 finally show ?thesis by simp |
782 finally show ?thesis by simp |
782 next |
783 next |
791 by (auto simp: median_def length_chop) |
792 by (auto simp: median_def length_chop) |
792 finally have x_eq: "x = median (map slow_median (chop 5 xs))" . |
793 finally have x_eq: "x = median (map slow_median (chop 5 xs))" . |
793 |
794 |
794 text \<open>The cost of computing the medians of all the subgroups:\<close> |
795 text \<open>The cost of computing the medians of all the subgroups:\<close> |
795 define T_ms where "T_ms = T_map T_slow_median (chop 5 xs)" |
796 define T_ms where "T_ms = T_map T_slow_median (chop 5 xs)" |
796 have "T_ms \<le> 9 * n + 45" |
797 have "T_ms \<le> 10 * n + 49" |
797 proof - |
798 proof - |
798 have "T_ms = (\<Sum>ys\<leftarrow>chop 5 xs. T_slow_median ys) + length (chop 5 xs) + 1" |
799 have "T_ms = (\<Sum>ys\<leftarrow>chop 5 xs. T_slow_median ys) + length (chop 5 xs) + 1" |
799 by (simp add: T_ms_def T_map_eq) |
800 by (simp add: T_ms_def T_map_eq) |
800 also have "(\<Sum>ys\<leftarrow>chop 5 xs. T_slow_median ys) \<le> (\<Sum>ys\<leftarrow>chop 5 xs. 44)" |
801 also have "(\<Sum>ys\<leftarrow>chop 5 xs. T_slow_median ys) \<le> (\<Sum>ys\<leftarrow>chop 5 xs. 48)" |
801 proof (intro sum_list_mono) |
802 proof (intro sum_list_mono) |
802 fix ys assume "ys \<in> set (chop 5 xs)" |
803 fix ys assume "ys \<in> set (chop 5 xs)" |
803 hence "length ys \<le> 5" |
804 hence "length ys \<le> 5" |
804 using length_chop_part_le by blast |
805 using length_chop_part_le by blast |
805 have "T_slow_median ys \<le> (length ys) ^ 2 + 3 * length ys + 4" |
806 have "T_slow_median ys \<le> (length ys) ^ 2 + 4 * length ys + 3" |
806 by (rule T_slow_median_le) |
807 by (rule T_slow_median_le) |
807 also have "\<dots> \<le> 5 ^ 2 + 3 * 5 + 4" |
808 also have "\<dots> \<le> 5 ^ 2 + 4 * 5 + 3" |
808 using \<open>length ys \<le> 5\<close> by (intro add_mono power_mono) auto |
809 using \<open>length ys \<le> 5\<close> by (intro add_mono power_mono) auto |
809 finally show "T_slow_median ys \<le> 44" by simp |
810 finally show "T_slow_median ys \<le> 48" by simp |
810 qed |
811 qed |
811 also have "(\<Sum>ys\<leftarrow>chop 5 xs. 44) + length (chop 5 xs) + 1 = |
812 also have "(\<Sum>ys\<leftarrow>chop 5 xs. 48) + length (chop 5 xs) + 1 = |
812 45 * nat \<lceil>real n / 5\<rceil> + 1" |
813 49 * nat \<lceil>real n / 5\<rceil> + 1" |
813 by (simp add: map_replicate_const length_chop) |
814 by (simp add: map_replicate_const length_chop) |
814 also have "\<dots> \<le> 9 * n + 45" |
815 also have "\<dots> \<le> 10 * n + 49" |
815 by linarith |
816 by linarith |
816 finally show "T_ms \<le> 9 * n + 45" by simp |
817 finally show "T_ms \<le> 10 * n + 49" by simp |
817 qed |
818 qed |
818 |
819 |
819 text \<open>The cost of the first recursive call (to compute the median of medians):\<close> |
820 text \<open>The cost of the first recursive call (to compute the median of medians):\<close> |
820 define T_rec1 where |
821 define T_rec1 where |
821 "T_rec1 = T_mom_select (((length xs + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs))" |
822 "T_rec1 = T_mom_select (((length xs + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs))" |
862 by (rule T'_mom_select_mono) |
863 by (rule T'_mom_select_mono) |
863 finally show ?thesis . |
864 finally show ?thesis . |
864 qed |
865 qed |
865 |
866 |
866 text \<open>Now for the final inequality chain:\<close> |
867 text \<open>Now for the final inequality chain:\<close> |
867 have "T_mom_select k xs = T_rec2 + T_rec1 + T_ms + n + nl + ne + T_chop 5 xs + 4" using False |
868 have "T_mom_select k xs \<le> T_rec2 + T_rec1 + T_ms + 2 * n + nl + ne + T_chop 5 xs + 5" using False |
868 by (subst T_mom_select.simps, unfold Let_def tw [symmetric] defs [symmetric]) |
869 by (subst T_mom_select.simps, unfold Let_def tw [symmetric] defs [symmetric]) |
869 (simp_all add: nl_def ne_def T_rec1_def T_rec2_def T_partition3_eq |
870 (simp_all add: nl_def ne_def T_rec1_def T_rec2_def T_partition3_eq |
870 T_length_eq T_ms_def) |
871 T_length_eq T_ms_def) |
871 also have "nl \<le> n" by (simp add: nl_def ls_def) |
872 also have "nl \<le> n" by (simp add: nl_def ls_def) |
872 also have "ne \<le> n" by (simp add: ne_def es_def) |
873 also have "ne \<le> n" by (simp add: ne_def es_def) |
873 also note \<open>T_ms \<le> 9 * n + 45\<close> |
874 also note \<open>T_ms \<le> 10 * n + 49\<close> |
874 also have "T_chop 5 xs \<le> 5 * n + 1" |
875 also have "T_chop 5 xs \<le> 5 * n + 1" |
875 using T_chop_le[of 5 xs] by simp |
876 using T_chop_le[of 5 xs] by simp |
876 also note \<open>T_rec1 \<le> T'_mom_select (nat \<lceil>0.2*n\<rceil>)\<close> |
877 also note \<open>T_rec1 \<le> T'_mom_select (nat \<lceil>0.2*n\<rceil>)\<close> |
877 also note \<open>T_rec2 \<le> T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>)\<close> |
878 also note \<open>T_rec2 \<le> T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>)\<close> |
878 finally have "T_mom_select k xs \<le> |
879 finally have "T_mom_select k xs \<le> |
879 T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>) + T'_mom_select (nat \<lceil>0.2*n\<rceil>) + 17 * n + 50" |
880 T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>) + T'_mom_select (nat \<lceil>0.2*n\<rceil>) + 19 * n + 55" |
880 by simp |
881 by simp |
881 also have "\<dots> = T'_mom_select n" |
882 also have "\<dots> = T'_mom_select n" |
882 using False by (subst T'_mom_select.simps) auto |
883 using False by (subst T'_mom_select.simps) auto |
883 finally show ?thesis by simp |
884 finally show ?thesis by simp |
884 qed |
885 qed |