(* File:IMO2019_Q5.thy Author:ManuelEberl,TUMünchen
*) section‹Q5› theory IMO2019_Q5 imports Complex_Main begin
text‹
Given a sequence $(c_1,\ldots, c_n)$ of coins, each of which can be heads (‹H›) or tails (‹T›),
Harry performs the following process: Let ‹k› be the number of coins that show ‹H›. If ‹k > 0›,
flip the ‹k›-th coin and repeat the process. Otherwise, stop.
What is the average number of steps that this process takes, averaged over all $2^n$
coin sequences of length ‹n›? ›
subsection‹Definition›
text‹
We represent coins as Booleans, where @{term True} indicates ‹H› and @{term False} indicates ‹T›.
Coin sequences are then simply lists of Booleans.
The following function flips the ‹i›-th coin in the sequence (in Isabelle, the convention is that
the first list element is indexed with 0). › definition flip :: "bool list ==> nat ==> bool list"where "flip xs i = xs[i := ¬xs ! i]"
lemma flip_Cons_pos [simp]: "n > 0 ==> flip (x # xs) n = x # flip xs (n - 1)" by (cases n) (auto simp: flip_def)
text‹
The following function computes the number of ‹H› in a coin sequence. › definition heads :: "bool list ==> nat"where"heads xs = length (filter id xs)"
text‹
The following function performs a single step of Harry's process. › definition harry_step :: "bool list ==> bool list"where "harry_step xs = flip xs (heads xs - 1)"
text‹
The following is the measure function for Harry's process, i.e. how many steps the process takes
to terminate starting from the given sequence. We define it like this now and prove the
correctness later. › function harry_meas where "harry_meas xs = (if xs = [] then 0 else if hd xs then 1 + harry_meas (tl xs) else if ¬last xs then harry_meas (butlast xs) else let n = length xs in harry_meas (take (n - 2) (tl xs)) + 2 * n - 1)" by auto terminationby (relation "Wellfounded.measure length") (auto simp: min_def)
lemmas [simp del] = harry_meas.simps
text‹
We now prove some simple properties of @{const harry_meas} and @{const harry_step}. ›
text‹
We prove a more convenient case distinction rule for lists that allows us to
distinguish between lists starting with @{term True}, ending with @{term False}, and
starting with @{term False} and ending with @{term True}. › lemma head_last_cases [case_names Nil True False False_True]: assumes"xs = [] ==> P" assumes"∧ys. xs = True # ys ==> P""∧ys. xs = ys @ [False] ==> P" "∧ys. xs = False # ys @ [True] ==> P" shows"P" proof -
consider "length xs = 0" | "length xs = 1" | "length xs ≥ 2"by linarith thus ?thesis proof cases assume"length xs = 1" hence"xs = [hd xs]"by (cases xs) auto thus P using assms(2)[of "[]"] assms(3)[of "[]"] by (cases "hd xs") auto next assume len: "length xs ≥ 2" from len obtain x xs' where *: "xs = x # xs'" by (cases xs) auto have **: "xs' = butlast xs' @ [last xs']" using len by (subst append_butlast_last_id) (auto simp: *) have [simp]: "xs = x # butlast xs' @ [last xs']" by (subst *, subst **) auto show P using assms(2)[of xs'] assms(3)[of "x # butlast xs'"] assms(4)[of "butlast xs'"] ** by (cases x; cases "last xs'") auto qed (use assms in auto) qed
lemma harry_meas_eq_0 [simp]: assumes"True ∉ set xs" shows"harry_meas xs = 0" using assms by (induction xs rule: rev_induct) auto
text‹
If the sequence starts with ‹H›, the process runs on the remaining sequence until it
terminates and then flips this ‹H› in another single step. › lemma harry_step_True_start [simp]: "harry_step (True # xs) = (if True ∈ set xs then True # harry_step xs else False # xs)" by (auto simp: harry_step_def)
text‹
If the sequence ends in ‹T›, the process simply runs on the remaining sequence as if it
were not present. › lemma harry_step_False_end [simp]: assumes"True ∈ set xs" shows"harry_step (xs @ [False]) = harry_step xs @ [False]" proof - have"harry_step (xs @ [False]) = flip (xs @ [False]) (heads xs - 1)" using heads_le_length[of xs] by (auto simp: harry_step_def) alsohave"… = harry_step xs @ [False]" using Suc_less_eq assms heads_le_length[of xs] by (subst flip_append1; fastforce simp: harry_step_def) finallyshow ?thesis . qed
text‹
If the sequence starts with ‹T› and ends with ‹H›, the process runs on the remaining
sequence inbetween as if these two were not present, eventually leaving a sequence that
consists entirely if ‹T› except for a single final ‹H›. › lemma harry_step_False_True: assumes"True ∈ set xs" shows"harry_step (False # xs @ [True]) = False # harry_step xs @ [True]" proof - have"harry_step (False # xs @ [True]) = False # flip (xs @ [True]) (heads xs - 1)" using assms heads_le_length[of xs] by (auto simp: harry_step_def heads_le_length) alsohave"… = False # harry_step xs @ [True]" using assms by (subst flip_append1)
(auto simp: harry_step_def Suc_less_SucD heads_le_length less_Suc_eq_le) finallyshow ?thesis . qed
text‹
That sequence consisting only of ‹T› except for a single final ‹H› is then turned into
an all-‹T› sequence in ‹2n+1› steps. › lemma harry_meas_Falses_True [simp]: "harry_meas (replicate n False @ [True]) = 2 * n + 1" proof (cases "n = 0") case False hence"replicate n False @ [True] = False # replicate (n - 1) False @ [True]" by (cases n) auto alsohave"harry_meas … = 2 * n + 1" using False by (simp add: harry_meas_False_True algebra_simps) finallyshow ?thesis . qed auto
text‹
We will now show that @{const harry_meas} indeed counts the length of the process.
As a first step, we will show that if there is a ‹H› in a sequence, applying a single step
decreases the measure by one. › lemma harry_meas_step_aux: assumes"True ∈ set xs" shows"harry_meas xs = Suc (harry_meas (harry_step xs))" using assms proof (induction xs rule: length_induct) case (1 xs) hence IH: "harry_meas ys = Suc (harry_meas (harry_step ys))" if"length ys < length xs""True ∈ set ys"for ys using that by blast
show ?case proof (cases xs rule: head_last_cases) case (True ys) thus ?thesis by (auto simp: IH) next case (False ys) thus ?thesis using"1.prems"by (auto simp: IH) next case (False_True ys) thus ?thesis proof (cases "True ∈ set ys") case False
define n where"n = length ys + 1" have"n > 0"by (simp add: n_def) from False have"ys = replicate (n - 1) False" unfolding n_def by (induction ys) auto with False_True ‹n > 0›have [simp]: "xs = replicate n False @ [True]" by (cases n) auto show ?thesis using‹n > 0›by auto qed (auto simp: IH False_True harry_step_False_True harry_meas_False_True) qed (use1in auto) qed
lemma harry_meas_step: "True ∈ set xs ==> harry_meas (harry_step xs) = harry_meas xs - 1" using harry_meas_step_aux[of xs] by simp
text‹
Next, we show that the measure is zero if and only if there is no ‹H› left in the sequence. › lemma harry_meas_eq_0_iff [simp]: "harry_meas xs = 0 ⟷ True ∉ set xs" proof (induction xs rule: length_induct) case (1 xs) show ?case by (cases xs rule: head_last_cases) (auto simp: 1 harry_meas_False_True 1) qed
text‹
It follows by induction that if the measure of a sequence is ‹n›, then iterating the step
less than ‹n› times yields a sequence with at least one ‹H› in it, but iterating it exactly ‹n› times yields a sequence that contains no more ‹H›. › lemma True_in_funpow_harry_step: assumes"n < harry_meas xs" shows"True ∈ set ((harry_step ^^ n) xs)" using assms proof (induction n arbitrary: xs) case0 show ?caseby (rule ccontr) (use0in auto) next case (Suc n) have"True ∈ set xs"by (rule ccontr) (use Suc in auto) have"(harry_step ^^ Suc n) xs = (harry_step ^^ n) (harry_step xs)" by (simp only: funpow_Suc_right o_def) alsohave"True ∈ set …" using Suc ‹True ∈ set xs›by (intro Suc) (auto simp: harry_meas_step) finallyshow ?case . qed
lemma True_notin_funpow_harry_step: "True ∉ set ((harry_step ^^ harry_meas xs) xs)" proof (induction"harry_meas xs" arbitrary: xs) case (Suc n) have"True ∈ set xs"by (rule ccontr) (use Suc in auto) have"(harry_step ^^ harry_meas xs) xs = (harry_step ^^ Suc n) xs" by (simp only: Suc) alsohave"… = (harry_step ^^ n) (harry_step xs)" by (simp only: funpow_Suc_right o_def) alsohave"… = (harry_step ^^ (harry_meas xs - 1)) (harry_step xs)" by (simp flip: Suc(2)) alsohave"harry_meas xs - 1 = harry_meas (harry_step xs)" using‹True ∈ set xs›by (subst harry_meas_step) auto alsohave"True ∉ set ((harry_step ^^ …) (harry_step xs))" using Suc ‹True ∈ set xs›by (intro Suc) (auto simp: harry_meas_step) finallyshow ?case . qed auto
text‹
This shows that the measure is indeed the correct one: It is the smallest number such that
iterating Harry's step that often yields a sequence with no heads in it. › theorem"harry_meas xs = (LEAST n. True ∉ set ((harry_step ^^ n) xs))" proof (rule sym, rule Least_equality, goal_cases) show"True ∉ set ((harry_step ^^ harry_meas xs) xs)" by (rule True_notin_funpow_harry_step) next case (2 y) show ?case by (rule ccontr) (use2 True_in_funpow_harry_step[of y] in auto) qed
subsection‹Average-case analysis›
text‹
The set of all coin sequences of a given length. › definition seqs where"seqs n = {xs :: bool list . length xs = n}"
lemma length_seqs [dest]: "xs ∈ seqs n ==> length xs = n" by (simp add: seqs_def)
text‹
The coin sequences of length ‹n + 1› are simply what is obtained by appending either ‹H›
or ‹T› to each coin sequence of length ‹n›. › lemma seqs_Suc [code]: "seqs (Suc n) = (λxs. True # xs) ` seqs n ∪ (λxs. False # xs) ` seqs n" by (auto simp: seqs_def length_Suc_conv)
text‹
The set of coin sequences of length ‹n› is invariant under reversal. › lemma seqs_rev [simp]: "rev ` seqs n = seqs n" proof show"rev ` seqs n ⊆ seqs n" by (auto simp: seqs_def) hence"rev ` rev ` seqs n ⊆ rev ` seqs n" by blast thus"seqs n ⊆ rev ` seqs n"by (simp add: image_image) qed
text‹
Hence we get a similar decomposition theorem that appends at the end. › lemma seqs_Suc': "seqs (Suc n) = (λxs. xs @ [True]) ` seqs n ∪ (λxs. xs @ [False]) ` seqs n" proof - have"rev ` rev ` ((λxs. xs @ [True]) ` seqs n ∪ (λxs. xs @ [False]) ` seqs n) = rev ` ((λxs. True # xs) ` rev ` seqs n ∪ (λxs. False # xs) ` rev ` seqs n)" unfolding image_Un image_image by simp alsohave"(λxs. True # xs) ` rev ` seqs n ∪ (λxs. False # xs) ` rev ` seqs n = seqs (Suc n)" by (simp add: seqs_Suc) finallyshow ?thesis by (simp add: image_image) qed
lemma card_seqs [simp]: "card (seqs n) = 2 ^ n" proof (induction n) case (Suc n) have"card (seqs (Suc n)) = card ((#) True ` seqs n ∪ (#) False ` seqs n)" by (auto simp: seqs_Suc) alsofrom Suc.IH have"… = 2 ^ Suc n" by (subst card_Un_disjoint) (auto simp: card_image) finallyshow ?case . qed auto
text‹
The sum of the measures over all possible coin sequences of a given length (defined
as a recurrence relation; correctness proven later). › fun harry_sum :: "nat ==> nat"where "harry_sum 0 = 0"
| "harry_sum (Suc 0) = 1"
| "harry_sum (Suc (Suc n)) = 2 * harry_sum (Suc n) + (2 * n + 4) * 2 ^ n"
lemma Suc_Suc_induct: "P 0 ==> P (Suc 0) ==> (∧n. P n ==> P (Suc n) ==> P (Suc (Suc n))) ==> P n" by induction_schema (pat_completeness, rule wf_measure[of id], auto)
text‹
The recurrence relation really does describe the sum over all measures: › lemma harry_sum_correct: "harry_sum n = sum harry_meas (seqs n)" proof (induction n rule: Suc_Suc_induct) case (3 n) have"seqs (Suc (Suc n)) = (λxs. xs @ [False]) ` seqs (Suc n) ∪ (λxs. True # xs @ [True]) ` seqs n ∪ (λxs. False # xs @ [True]) ` seqs n" by (subst (1) seqs_Suc, subst (12) seqs_Suc') (simp add: image_Un image_image Un_ac seqs_Suc) alsohave"int (sum harry_meas …) = int (harry_sum (Suc n)) + int (∑xs∈seqs n. 1 + harry_meas (xs @ [True])) + int (∑xs∈seqs n. harry_meas (False # xs @ [True]))" by (subst sum.union_disjoint sum.reindex, auto simp: inj_on_def 3)+ alsohave"int (∑xs∈seqs n. 1 + harry_meas (xs @ [True])) = 2 ^ n + int (∑xs∈seqs n. harry_meas (xs @ [True]))" by (subst sum.distrib) auto alsohave"(∑xs∈seqs n. harry_meas (False # xs @ [True])) = harry_sum n + (2 * n + 3) * 2 ^ n" by (auto simp: 3 harry_meas_False_True sum.distrib algebra_simps length_seqs) alsohave"harry_sum (Suc n) = (∑xs∈seqs n. harry_meas (xs @ [True])) + harry_sum n" unfolding seqs_Suc' 3by (subst sum.union_disjoint sum.reindex, auto simp: inj_on_def)+ hence"int (∑xs∈seqs n. harry_meas (xs @ [True])) = int (harry_sum (Suc n)) - int (harry_sum n)" by simp finallyhave"int (∑x∈seqs (Suc (Suc n)). harry_meas x) = int (2 * harry_sum (Suc n) + (2 * n + 4) * 2 ^ n)" unfolding of_nat_add by (simp add: algebra_simps) hence"(∑x∈seqs (Suc (Suc n)). (harry_meas x)) = (2 * harry_sum (Suc n) + (2 * n + 4) * 2 ^ n)"by linarith thus ?caseby simp qed (auto simp: seqs_Suc)
lemma harry_sum_closed_form_aux: "4 * harry_sum n = n * (n + 1) * 2 ^ n" by (induction n rule: harry_sum.induct) (auto simp: algebra_simps)
text‹
Solving the recurrence gives us the following solution: › theorem harry_sum_closed_form: "harry_sum n = n * (n + 1) * 2 ^ n div 4" using harry_sum_closed_form_aux[of n] by simp
text‹
The average is now a simple consequence: › definition harry_avg where"harry_avg n = harry_sum n / card (seqs n)"
corollary"harry_avg n = n * (n + 1) / 4" proof - have"real (4 * harry_sum n) = n * (n + 1) * 2 ^ n" by (subst harry_sum_closed_form_aux) auto hence"real (harry_sum n) = n * (n + 1) * 2 ^ n / 4" by (simp add: field_simps) thus ?thesis by (simp add: harry_avg_def field_simps) qed
end
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.