(*-------------------------------------------* | Uniform Candy Distribution | | Isabelle 2011 | | Yoshinao Isobe (AIST JAPAN) | | 13 November 2011 | *-------------------------------------------*) (* ................................................................... * There are N children sitting in a circle, where each child has an even number of candies. The following step is repeated indefinitely: every child passes half of their candies to the child on their left; any child who ends up with an odd number of candies is given another candy by the teacher. Then, prove that eventually every child will hold the same number of candies. References: - TPPmark 2011 http://staff.aist.go.jp/reynald.affeldt/tpp2011/ucd.html - The Puzzle TOAD http://www.cs.cmu.edu/puzzle/puzzle6.html * ................................................................... *) theory UCD_Isabelle2011 imports Complex_Main begin declare Min_ge_iff [simp del] declare Max_le_iff [simp del] declare Max_less_iff [simp del] (* =================================================================== * | | | Preliminary | | | * =================================================================== *) (* -------------------------------------------------- * | list decomposition | * -------------------------------------------------- *) lemma list_nth_decompo: "ALL s. i < length s --> (EX s0 s1. length s0 = i & s = s0 @ (s!i) # s1)" apply (induct_tac i, auto) (* base case *) apply (rule_tac x="tl s" in exI) apply (simp add: hd_conv_nth[THEN sym]) (* step case *) apply (case_tac "s=[]", simp) apply (drule_tac x="tl s" in spec) apply (drule mp, force) apply (elim conjE exE) apply (rule_tac x="hd s # s0" in exI) apply (auto simp add: neq_Nil_conv) done (* -------------------------------------------------- * | max, min, num, stable on list | * -------------------------------------------------- *) abbreviation maxList :: "nat list => nat" where "maxList s == Max (set s)" abbreviation minList :: "nat list => nat" where "minList s == Min (set s)" primrec numList :: "nat => nat list => nat" where "numList m ([]) = 0" |"numList m (n#s) = (if (m=n) then (Suc (numList m s)) else numList m s)" lemma num_test: "numList 2 [4, 2, 10, 2, 5, 2] = 3" by (simp) definition stableList :: "nat list => bool" where stableList_def: "stableList s == ALL n:set s. n = minList s" (* -------------------------------------- * | basic lemmas on min, num, and stable | * -------------------------------------- *) lemma min_le_eq: "i < length s ==> (s ! i <= minList s) = (s ! i = minList s)" by (auto, rule antisym, auto) lemma num_append: "numList m(s @ t) = numList m s + numList m t" by (induct_tac s, auto) lemma num_zero_not_eq: "(numList m s = 0) = (ALL i s!i = m)) --> numList m t <= numList m s" apply (induct_tac s) apply (auto simp add: length_Suc_conv) apply (drule_tac x="ys" in spec, auto) apply (drule_tac x="ys" in spec, auto) apply (drule_tac x="ys" in spec, auto) done lemma num_less_lm: "[| length t0 = length s0; length t1 = length s1; n ~= m ; ALL i (s0 @ m # s1)!i = m |] ==> numList m (t0 @ n # t1) < numList m (s0 @ m # s1)" apply (simp add: num_append, simp add: num_append[THEN sym]) apply (simp add: less_Suc_eq_le) apply (rule num_le) apply (auto) apply (case_tac "i s!i = m |] ==> numList m t < numList m s" apply (insert list_nth_decompo[of j]) apply (frule_tac x="s" in spec) apply (drule_tac x="t" in spec) apply (simp) apply (elim conjE exE, simp) apply (rule num_less_lm, auto) done lemma num_zero_not_min: "[| s ~= [] ; numList m s = 0 |] ==> (m ~= minList s)" apply (simp add: num_zero_not_eq) apply (insert in_set_conv_nth[of m s], auto) done lemma not_stable_not_nil: "~ stableList s ==> s ~= []" by (auto simp add: stableList_def) (* --------------------------- * | lemmas on nth and num | * --------------------------- *) lemma nth_min_lm[rule_format]: "(s ! i = minList s & i+j < length s & (ALL i. s ! i = minList s --> i < length s - Suc 0 --> s ! Suc i = minList s)) --> s ! (i+j) = minList s" by (induct_tac j, auto) lemma nth_min: "[| s ! i = minList s ; i <= j ; j < length s ; ALL i. s ! i = minList s --> i < length s - Suc 0 --> s ! Suc i = minList s |] ==> s ! j = minList s" by (insert nth_min_lm[of s i "j - i"], simp) lemma nth_min_less_lm: "[| s ! 0 = minList s | minList s < s ! (length s - Suc 0) ; ~ stableList s |] ==> EX i. i < length s - Suc 0 & s ! i = minList s & minList s < s ! (Suc i)" apply (erule disjE) (* s ! 0 = minList s *) apply (erule contrapos_np) apply (simp add: stableList_def) apply (auto simp add: in_set_conv_nth) apply (simp add: not_less) apply (rule nth_min) apply (auto simp add: min_le_eq) (* minList s < s ! (length s - Suc 0) *) apply (rotate_tac 1) apply (erule contrapos_pp) apply (simp add: not_less) apply (subgoal_tac "EX i. i (minList s < s ! 0 & s ! (length s - Suc 0) = minList s) | (EX i. i < length s - Suc 0 & s ! i = minList s & minList s < s ! (Suc i))" apply (case_tac "minList s < s ! 0 & s ! (length s - Suc 0) = minList s") (* disj 1 *) apply (simp (* disj 2 *)) apply (subgoal_tac "0 < length s") apply (rule disjI2) apply (simp del: disj_not1) apply (erule disjE) (* ~ minList s < s ! 0 *) apply (rule nth_min_less_lm) apply (simp_all) apply (simp add: not_less) apply (simp add: min_le_eq) (* s ! (length s - Suc 0) ~= minList s *) apply (rule nth_min_less_lm) apply (simp_all) apply (simp add: less_le, simp) apply (auto simp add: stableList_def) done (* nth_min_less_hd is used for lemma 4 *) lemma nth_min_less_hd: "~ stableList s ==> EX i. i ('a => 'a) => ('a => 'a)" where "repeat 0 = (%f. id)" |"repeat (Suc k) = (%f. (repeat k f) o f)" (* -------------------------- * | basic lemmas on repeat | * -------------------------- *) lemma length_repeat: "ALL t. length (f t) = length t ==> ALL s. length(repeat k f s) = length s" by (induct_tac k, auto) lemma repeat_nil: "ALL t. length (f t) = length t ==> (repeat k f s = []) = (s = [])" apply (subgoal_tac "(length(repeat k f s) = 0) = (length s = 0)") apply (simp) apply (simp add: length_repeat) done lemma repeat_assoc: "ALL s. (repeat k f (f s)) = f (repeat k f s)" by (induct_tac k, auto) lemma min_repeat_le: "(ALL k. minList ((repeat k f) s) <= minList ((repeat (Suc k) f) s)) --> minList s <= minList ((repeat k f) s)" apply (induct_tac k) apply (auto) apply (drule_tac x="n" in spec) apply (simp add: repeat_assoc) done lemma repeat_repeat_append: "ALL s. repeat k0 f (repeat k1 f s) = repeat (k0+k1) f s" apply (induct_tac k0) apply (auto) apply (drule_tac x="f s" in spec) apply (simp add: repeat_assoc) done (* --------------------------- * | lemmas on num and repeat | * --------------------------- *) lemma num_repeat_zero_lm[rule_format]: "ALL s. (numList m s <= n & (ALL k. 0 < numList m ((repeat k f) s) --> (numList m ((repeat (Suc k) f) s) < numList m ((repeat k f) s)))) --> (EX k. numList m ((repeat k f) s) = 0)" apply (induct_tac n) (* base *) apply (intro allI impI, rule_tac x="0" in exI, simp) (* step *) apply (intro allI impI) apply (simp) apply (case_tac "(EX k. numList m ((repeat k f) s) = 0)", simp) apply (drule_tac x="(f s)" in spec) apply (elim conjE exE) apply (drule mp) apply (rule conjI) (* conj 1 *) apply (drule_tac x="0" in spec) apply (simp) apply (drule_tac x="0" in spec) apply (simp) (* conj 2 *) apply (intro allI) apply (drule_tac x="Suc k" in spec) apply (simp) apply (erule exE) apply (rule_tac x="Suc k" in exI) apply (simp) done lemma num_repeat_zero: "ALL k. 0 < numList m ((repeat k f) s) --> (numList m ((repeat (Suc k) f) s) < numList m ((repeat k f) s)) ==> EX k. numList m ((repeat k f) s) = 0" by (rule num_repeat_zero_lm, auto) (* =================================================================== * | | | Uniform Candy Distribution | | | * =================================================================== *) (* -------------------------------------------------- * | definition | * -------------------------------------------------- *) definition allEven :: "nat list => bool" where allEven_def : "allEven s == (ALL s:set s. even s)" definition fill :: "nat => nat" where fill_def : "fill c == if even c then c else c+1" definition nextOne :: "nat => nat => nat" where nextOne_def : "nextOne c0 c1 == fill(c0 div 2 + c1 div 2)" primrec nextList :: "nat => (nat list) => (nat list)" where "nextList 0 s = []" | "nextList (Suc i) s = (nextList i s) @ [nextOne (s ! i) (s ! (Suc i))]" definition nextCirc :: "(nat list) => (nat list)" where nextCirc_def: "nextCirc s == nextList (length s) (s @ [hd s])" (* ------ test ------ *) lemma "nextList (Suc (Suc (Suc 0))) [4, 2, 10, 4] = [4, 6, 8]" by (simp add: nextOne_def fill_def) lemma "nextCirc [4, 2, 10] = [4, 6, 8]" by (simp add: nextCirc_def nextOne_def fill_def) (* -------------------------------------------------- * | lemmas on nextOne | * -------------------------------------------------- *) lemma min_nextOne_eq: "even c ==> nextOne c c = c" apply (auto simp add: fill_def nextOne_def even_mult_two_ex) apply (drule_tac x="m" in spec, simp) done lemma min_nextOne_le1: "[| even c0; even c1; c0 <= c1 |] ==> c0 <= nextOne c0 c1" by (auto simp add: fill_def nextOne_def even_mult_two_ex) lemma min_nextOne_le2: "[| even c0; even c1; c0 <= c1 |] ==> c0 <= nextOne c1 c0" by (auto simp add: fill_def nextOne_def even_mult_two_ex) lemma min_nextOne_le: "[| even c0; even c1 |] ==> min c0 c1 <= nextOne c0 c1" by (auto simp add: fill_def nextOne_def even_mult_two_ex) lemma max_nextOne_le1: "[| even c0; even c1; c0 <= c1 |] ==> nextOne c0 c1 <= c1" apply (simp add: fill_def nextOne_def) apply (auto simp add: even_mult_two_ex) apply (case_tac "2 * mb < ma", auto) apply (case_tac "m < 2 * mb", auto) done lemma max_nextOne_le2: "[| even c0; even c1; c0 <= c1 |] ==> nextOne c1 c0 <= c1" apply (simp add: fill_def nextOne_def) apply (auto simp add: even_mult_two_ex) apply (case_tac "m < 2 * mb", auto) apply (case_tac "2 * mb < ma", auto) done lemma max_nextOne_le: "[| even c0; even c1 |] ==> nextOne c0 c1 <= max c0 c1" by (simp add: max_def max_nextOne_le1 max_nextOne_le2) lemma min_nextOne_less1: "[| even c0; even c1; c0 < c1 |] ==> c0 < nextOne c0 c1" by (auto simp add: fill_def nextOne_def even_mult_two_ex) lemma min_nextOne_less2: "[| even c0; even c1; c0 < c1 |] ==> c0 < nextOne c1 c0" by (auto simp add: fill_def nextOne_def even_mult_two_ex) lemma min_nextOne_less: "[| even c0; even c1; c0 ~= c1 |] ==> min c0 c1 < nextOne c0 c1" by (auto simp add: min_def min_nextOne_less1 min_nextOne_less2) lemma even_nextOne: "even (nextOne c0 c1)" by (auto simp add: fill_def nextOne_def) (* -------------------------------------------------- * | lemmas on nextLine | * -------------------------------------------------- *) lemma length_nextList[rule_format]: "i < length s --> length (nextList i s) = i" by (induct_tac i, simp+) lemma nth_nextList_nextOne_diff[rule_format]: "Suc (i+j) < length s --> nextList (Suc (i+j)) s ! i = nextOne (s ! i) (s ! (Suc i))" by (induct_tac j, auto simp add: nth_append length_nextList) lemma nth_nextList_nextOne: "[| Suc n < length s ; i <= n |] ==> nextList (Suc n) s ! i = nextOne (s ! i) (s ! (Suc i))" by (insert nth_nextList_nextOne_diff[of i "n - i"], simp) (* -------------------------------------------------- * | lemmas on nextCirc | * -------------------------------------------------- *) lemma nth_nextCirc_nextOne: "i < length s ==> (nextCirc s) ! i = nextOne (s ! i) ((s @ [hd s]) ! (Suc i))" apply (simp add: nextCirc_def) apply (insert nth_nextList_nextOne[of "length s - 1" "s @ [hd s]" i]) apply (subgoal_tac "(EX m. length s = Suc m)", erule exE) apply (simp add: nth_append del: nextList.simps) apply (auto simp add: gr0_conv_Suc[THEN sym]) done lemma length_nextCirc: "length (nextCirc s) = length s" by (simp add: nextCirc_def length_nextList) lemma length_nextCirc_not_nil: "(nextCirc s = []) = (s = [])" apply (subgoal_tac "(length(nextCirc s) = 0) = (length s = 0)") apply (simp only: length_0_conv) apply (simp add: length_nextCirc) done lemma even_nextCirc: "allEven (nextCirc s)" apply (auto simp add: allEven_def in_set_conv_nth length_nextCirc) apply (simp add: nth_nextCirc_nextOne) apply (simp add: even_nextOne) done (* -------------------------------------------------- * | lemma 1 (max : not increase) | * -------------------------------------------------- *) lemma nextCirc_max_le: "[| allEven s ; s ~= [] |] ==> maxList (nextCirc s) <= maxList s" apply (subgoal_tac "EX i. i minList s <= minList (nextCirc s)" apply (subgoal_tac "EX i. i ALL i < length s. minList s < s!i --> minList s < (nextCirc s)!i" apply (intro allI impI) apply (subgoal_tac "s ~= []") apply (simp add: nth_nextCirc_nextOne) apply (case_tac "(s @ [hd s]) ! Suc i = s ! i") apply (simp add: allEven_def min_nextOne_eq) apply (rule le_less_trans) defer apply (rule min_nextOne_less) apply (auto simp add: allEven_def nth_append) done (* -------------------------------------------------- * | lemma 4 (min : increase) | * -------------------------------------------------- *) lemma nextCirc_min_less: "[| allEven s ; ~ stableList s |] ==> EX i. i < length s & s!i = minList s & s!i < (nextCirc s)!i" apply (insert nth_min_less_hd[of s], simp) apply (elim conjE exE) apply (rule_tac x="i" in exI) apply (simp add: length_nextCirc nth_nextCirc_nextOne) apply (rule min_nextOne_less1) apply (auto simp add: allEven_def nth_append not_stable_not_nil) done (* -------------------------------------------------- * | lemma 5 (num: decrease) | * -------------------------------------------------- *) lemma nextCirc_num_less: "[| allEven s ; ~ stableList s |] ==> numList (minList s) (nextCirc s) < numList (minList s) s" apply (insert nextCirc_min_less[of s], simp) apply (insert nextCirc_gt_min[of s], simp) apply (elim conjE exE) apply (rule num_less) apply (simp add: length_nextCirc) apply (simp)+ apply (intro allI impI) apply (rotate_tac -1) apply (erule contrapos_pp) apply (drule_tac x="ia" in spec) apply (simp add: less_le) done (* -------------------------------------------------- * | basic lemmas on (repeat nextCirc) | * -------------------------------------------------- *) lemma even_repeat_nextCirc: "allEven s ==> allEven (repeat k nextCirc s)" apply (induct_tac k) apply (simp add: even_nextCirc) apply (simp add: repeat_assoc even_nextCirc) done lemma length_repeat_nextCirc: "ALL s. length (repeat k nextCirc s) = length s" by (induct_tac k, auto simp add: length_nextCirc) lemma repeat_nextCirc_not_nil: "((repeat k nextCirc s) = []) = (s = [])" apply (subgoal_tac "(length(repeat k nextCirc s) = 0) = (length s = 0)") apply (simp only: length_0_conv) apply (simp add: length_repeat_nextCirc) done lemma not_stable_repeat_nextCirc_not_nil: "ALL k. ~stableList (repeat k nextCirc s) ==> s ~= []" apply (drule_tac x="0" in spec) apply (simp add: not_stable_not_nil) done (* --- min le --- *) lemma min_repeat_nextCirc_le: "ALL s. (allEven s & s ~= []) --> minList s <= minList (repeat k nextCirc s)" apply (induct_tac k) (* base *) apply (simp add: nextCirc_min_le) (* step *) apply (intro allI impI) apply (drule_tac x="nextCirc s" in spec) apply (simp_all add: even_nextCirc length_nextCirc_not_nil) apply (rule order_trans) apply (rule nextCirc_min_le) apply (simp_all) done (* --- max le --- *) lemma max_repeat_nextCirc_le: "ALL s. (allEven s & s ~= []) --> maxList (repeat k nextCirc s) <= maxList s" apply (induct_tac k) (* base *) apply (simp add: nextCirc_max_le) (* step *) apply (intro allI impI) apply (drule_tac x="nextCirc s" in spec) apply (simp_all add: even_nextCirc length_nextCirc_not_nil) apply (rule order_trans) apply (simp) apply (simp add: nextCirc_max_le) done (* -------------------------------------------------- * | lemmas (min: less) | * -------------------------------------------------- *) lemma min_repeat_nextCirc_eq_min: "[| allEven s ; s ~= [] ; 0 < numList (minList s) (repeat k nextCirc s) |] ==> minList (repeat k nextCirc s) = minList s" apply (auto simp add: num_not_zero_ex) apply (rule antisym) apply (rotate_tac -1, drule sym) apply (simp) apply (simp add: min_repeat_nextCirc_le) done lemma num_repeat_nextCirc_zero: "ALL s. (allEven s & (ALL k. ~stableList (repeat k nextCirc s))) --> (EX k. numList (minList s) (repeat k nextCirc s) = 0)" apply (intro allI impI) apply (rule num_repeat_zero) apply (auto) apply (simp add: repeat_assoc) apply (subgoal_tac " numList (minList (repeat k nextCirc s)) (nextCirc (repeat k nextCirc s)) < numList (minList (repeat k nextCirc s)) (repeat k nextCirc s)") apply (simp add: not_stable_repeat_nextCirc_not_nil min_repeat_nextCirc_eq_min) apply (simp add: nextCirc_num_less even_repeat_nextCirc) done lemma min_repeat_nextCirc_less: "ALL s. (allEven s & (ALL k. ~stableList (repeat k nextCirc s))) --> (EX k. minList s < minList ((repeat k nextCirc) s))" apply (intro allI impI) apply (insert num_repeat_nextCirc_zero) apply (drule_tac x="s" in spec) apply (simp) apply (erule exE) apply (rule_tac x="k" in exI) apply (simp add: num_zero_not_eq) apply (simp (no_asm_simp) add: less_le) apply (simp add: not_stable_repeat_nextCirc_not_nil min_repeat_nextCirc_le) apply (rotate_tac 1) apply (erule contrapos_pn) apply (simp add: in_set_conv_nth[THEN sym]) apply (simp add: not_stable_repeat_nextCirc_not_nil repeat_nextCirc_not_nil) done (* -------------------------------------------------- * | lemmas (min: repeat increase) | * -------------------------------------------------- *) lemma min_repeat_nextCirc_inc: "[| allEven s ; ALL k. ~stableList (repeat k nextCirc s) |] ==> EX k. minList s + any < minList ((repeat k nextCirc) s)" apply (induct_tac any) (* base *) apply (simp add: min_repeat_nextCirc_less) (* step *) apply (erule exE) apply (insert min_repeat_nextCirc_less) apply (drule_tac x="(repeat k nextCirc s)" in spec) apply (simp add: repeat_repeat_append) apply (drule mp) apply (simp add: even_repeat_nextCirc) apply (elim conjE exE) apply (rule_tac x="ka + k" in exI) apply (auto) done (* -------------------------------------------------- * | Theorem: eventually stable | * -------------------------------------------------- *) theorem eventually_stable: "[| allEven s ; s ~= [] |] ==> EX k. stableList (repeat k nextCirc s)" apply (case_tac "EX k. stableList (repeat k nextCirc s)", simp) (* if it never reaches a stable state *) apply (insert min_repeat_nextCirc_inc[of s "maxList s - minList s"]) apply (simp) apply (elim conjE exE) apply (rotate_tac -1) apply (erule contrapos_pp) apply (simp add: not_less) apply (subgoal_tac "minList (repeat k nextCirc s) <= maxList (repeat k nextCirc s)") apply (rule order_trans) apply (assumption) apply (simp add: repeat_nextCirc_not_nil) apply (simp add: max_repeat_nextCirc_le) apply (simp add: repeat_nextCirc_not_nil) done (* ----------------------------------------------- *) declare Min_ge_iff [simp] declare Max_le_iff [simp] declare Max_less_iff [simp] end