Theory Energy_Game
section ‹Energy Games›
theory Energy_Game
imports Coinductive.Coinductive_List Open_Induction.Restricted_Predicates
begin
text‹Energy games are two-player zero-sum games with perfect information played on labeled directed graphs.
The labels contain information on how each edge affects the current energy.
We call the two players attacker and defender.
In this theory we give fundamental definitions of plays, energy levels and (winning) attacker strategies.
(This corresponds to section 2.1 and 2.2 in the preprint~\cite{preprint}.)›
locale energy_game =
fixes attacker :: "'position set" and
weight :: "'position ⇒ 'position ⇒ 'label option" and
application :: "'label ⇒ 'energy ⇒ 'energy option"
begin
abbreviation "positions ≡ {g. g ∈ attacker ∨ g ∉ attacker}"
abbreviation "apply_w g g' ≡ application (the (weight g g'))"
text‹\subsubsection*{Plays}
A play is a possibly infinite walk in the underlying directed graph.›
coinductive valid_play :: "'position llist ⇒ bool" where
"valid_play LNil" |
"valid_play (LCons v LNil)" |
"⟦weight v (lhd Ps) ≠ None; valid_play Ps; ¬lnull Ps⟧
⟹ valid_play (LCons v Ps)"
text‹The following lemmas follow directly from the definition ‹valid_play›.
In particular, a play is valid if and only if for each position there is an edge to its successor
in the play. We show this using the coinductive definition by first establishing coinduction. ›
lemma valid_play_append:
assumes "valid_play (LCons v Ps)" and "lfinite (LCons v Ps)" and
"weight (llast (LCons v Ps)) v' ≠ None" and "valid_play (LCons v' Ps')"
shows "valid_play (lappend (LCons v Ps) (LCons v' Ps'))"
using assms proof(induction "list_of Ps" arbitrary: v Ps)
case Nil
then show ?case using valid_play.simps
by (metis lappend_code(2) lappend_lnull1 lfinite_LCons lhd_LCons lhd_LCons_ltl list.distinct(1) list_of_LCons llast_singleton llist.collapse(1) llist.disc(2))
next
case (Cons a x)
then show ?case using valid_play.simps
by (smt (verit) lappend_code(2) lfinite_LCons lfinite_llist_of lhd_lappend list_of_llist_of llast_LCons llist.discI(2) llist.distinct(1) llist_of.simps(2) llist_of_list_of ltl_simps(2) valid_play.intros(3))
qed
lemma valid_play_coinduct:
assumes "Q p" and
"⋀v Ps. Q (LCons v Ps) ⟹ Ps≠LNil ⟹ Q Ps ∧ weight v (lhd Ps) ≠ None"
shows "valid_play p"
using assms proof(coinduction arbitrary: p)
case valid_play
then show ?case
proof (cases "p = LNil")
case True
then show ?thesis by simp
next
case False
then show ?thesis
proof(cases "(∃v. p = LCons v LNil)")
case True
then show ?thesis by simp
next
case False
hence "∃v Ps. p = LCons v Ps ∧ ¬ lnull Ps" using ‹¬p = LNil›
by (metis llist.collapse(1) not_lnull_conv)
from this obtain v Ps where "p = LCons v Ps ∧ ¬ lnull Ps" by blast
hence "Q Ps ∧ weight v (lhd Ps) ≠ None" using valid_play
using llist.disc(1) by blast
then show ?thesis using valid_play.simps valid_play
using ‹p = LCons v Ps ∧ ¬ lnull Ps› by blast
qed
qed
qed
lemma valid_play_nth_not_None:
assumes "valid_play p" and "Suc i < llength p"
shows "weight (lnth p i) (lnth p (Suc i)) ≠ None"
proof-
have "∃prefix p'. p = lappend prefix p' ∧ llength prefix = Suc i ∧ weight (llast prefix) (lhd p') ≠ None ∧ valid_play p'"
using assms proof(induct i)
case 0
hence "∃v Ps. p = LCons v Ps"
by (metis llength_LNil neq_LNil_conv not_less_zero)
from this obtain v Ps where "p = LCons v Ps" by auto
hence "p = lappend (LCons v LNil) Ps"
by (simp add: lappend_code(2))
have "llength (LCons v LNil) = Suc 0" using one_eSuc one_enat_def by simp
have "weight v (lhd Ps) ≠ None" using 0 valid_play.simps ‹p = LCons v Ps›
by (smt (verit) One_nat_def add.commute gen_llength_code(1) gen_llength_code(2) less_numeral_extra(4) lhd_LCons llength_code llist.distinct(1) ltl_simps(2) one_enat_def plus_1_eq_Suc)
hence "p = lappend (LCons v LNil) Ps ∧ llength (LCons v LNil) = Suc 0 ∧ weight (llast (LCons v LNil)) (lhd Ps) ≠ None" using ‹p = LCons v Ps›
using ‹p = lappend (LCons v LNil) Ps› ‹llength (LCons v LNil) = Suc 0›
by simp
hence "p = lappend (LCons v LNil) Ps ∧ llength (LCons v LNil) = Suc 0 ∧ weight (llast (LCons v LNil)) (lhd Ps) ≠ None ∧ valid_play Ps" using valid_play.simps 0
by (metis (no_types, lifting) ‹p = LCons v Ps› llist.distinct(1) ltl_simps(2))
then show ?case by blast
next
case (Suc l)
hence "∃prefix p'. p = lappend prefix p' ∧ llength prefix = enat (Suc l) ∧ weight (llast prefix) (lhd p') ≠ None ∧ valid_play p'"
using Suc_ile_eq order_less_imp_le by blast
from this obtain prefix p' where P: "p = lappend prefix p' ∧ llength prefix = enat (Suc l) ∧ weight (llast prefix) (lhd p') ≠ None ∧ valid_play p'" by auto
have "p = lappend (lappend prefix (LCons (lhd p') LNil)) (ltl p') ∧ llength (lappend prefix (LCons (lhd p') LNil)) = enat (Suc (Suc l)) ∧ weight (llast (lappend prefix (LCons (lhd p') LNil))) (lhd (ltl p')) ≠ None ∧ valid_play (ltl p')"
proof
show "p = lappend (lappend prefix (LCons (lhd p') LNil)) (ltl p')" using P
by (metis Suc.prems(2) enat_ord_simps(2) lappend_LNil2 lappend_snocL1_conv_LCons2 lessI llist.exhaust_sel order.asym)
show "llength (lappend prefix (LCons (lhd p') LNil)) = enat (Suc (Suc l)) ∧
weight (llast (lappend prefix (LCons (lhd p') LNil))) (lhd (ltl p')) ≠ None ∧ valid_play (ltl p')"
proof
have "llength (lappend prefix (LCons (lhd p') LNil)) = 1+ (llength prefix)"
by (smt (verit, best) add.commute epred_1 epred_inject epred_llength llength_LNil llength_eq_0 llength_lappend llist.disc(2) ltl_simps(2) zero_neq_one)
thus "llength (lappend prefix (LCons (lhd p') LNil)) = enat (Suc (Suc l))" using P
by (simp add: one_enat_def)
show "weight (llast (lappend prefix (LCons (lhd p') LNil))) (lhd (ltl p')) ≠ None ∧ valid_play (ltl p') "
proof
show "weight (llast (lappend prefix (LCons (lhd p') LNil))) (lhd (ltl p')) ≠ None" using P valid_play.simps
by (metis Suc.prems(2) ‹llength (lappend prefix (LCons (lhd p') LNil)) = 1 + llength prefix› ‹llength (lappend prefix (LCons (lhd p') LNil)) = enat (Suc (Suc l))› ‹p = lappend (lappend prefix (LCons (lhd p') LNil)) (ltl p')› add.commute enat_add_mono eq_LConsD lappend_LNil2 less_numeral_extra(4) llast_lappend_LCons llast_singleton llength_eq_enat_lfiniteD ltl_simps(1))
show "valid_play (ltl p')" using P valid_play.simps
by (metis (full_types) energy_game.valid_play.intros(1) ltl_simps(1) ltl_simps(2))
qed
qed
qed
then show ?case by blast
qed
thus ?thesis
by (smt (z3) assms(2) cancel_comm_monoid_add_class.diff_cancel eSuc_enat enat_ord_simps(2) lappend_eq_lappend_conv lappend_lnull2 lessI lhd_LCons_ltl linorder_neq_iff llast_conv_lnth lnth_0 lnth_lappend the_enat.simps)
qed
lemma valid_play_nth:
assumes "⋀i. enat (Suc i) < llength p
⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None"
shows "valid_play p"
using assms proof(coinduction arbitrary: p rule: valid_play_coinduct)
show "⋀v Ps p.
LCons v Ps = p ⟹
∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None ⟹
Ps ≠ LNil ⟹
(∃p. Ps = p ∧ (∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None)) ∧
weight v (lhd Ps) ≠ None"
proof-
fix v Ps p
show "LCons v Ps = p ⟹
∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None ⟹
Ps ≠ LNil ⟹
(∃p. Ps = p ∧ (∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None)) ∧
weight v (lhd Ps) ≠ None"
proof-
assume "LCons v Ps = p"
show "∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None ⟹
Ps ≠ LNil ⟹
(∃p. Ps = p ∧ (∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None)) ∧
weight v (lhd Ps) ≠ None"
proof-
assume A: "∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None"
show "Ps ≠ LNil ⟹
(∃p. Ps = p ∧ (∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None)) ∧
weight v (lhd Ps) ≠ None"
proof-
assume "Ps ≠ LNil"
show "(∃p. Ps = p ∧ (∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None)) ∧
weight v (lhd Ps) ≠ None"
proof
show "∃p. Ps = p ∧ (∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None)"
proof
have "(∀i. enat (Suc i) < llength Ps ⟶ weight (lnth Ps i) (lnth Ps (Suc i)) ≠ None)"
proof
fix i
show "enat (Suc i) < llength Ps ⟶ weight (lnth Ps i) (lnth Ps (Suc i)) ≠ None "
proof
assume "enat (Suc i) < llength Ps"
hence "enat (Suc (Suc i)) < llength (LCons v Ps)"
by (metis ldropn_Suc_LCons ldropn_eq_LNil linorder_not_le)
have "(lnth Ps i) = (lnth (LCons v Ps) (Suc i))" by simp
have "(lnth Ps (Suc i)) = (lnth (LCons v Ps) (Suc (Suc i)))" by simp
thus "weight (lnth Ps i) (lnth Ps (Suc i)) ≠ None"
using A ‹(lnth Ps i) = (lnth (LCons v Ps) (Suc i))›
using ‹LCons v Ps = p› ‹enat (Suc (Suc i)) < llength (LCons v Ps)› by auto
qed
qed
thus "Ps = Ps ∧ (∀i. enat (Suc i) < llength Ps ⟶ weight (lnth Ps i) (lnth Ps (Suc i)) ≠ None)"
by simp
qed
have "v = lnth (LCons v Ps) 0" by simp
have "lhd Ps = lnth (LCons v Ps) (Suc 0)" using lnth_def ‹Ps ≠ LNil›
by (metis llist.exhaust_sel lnth_0 lnth_Suc_LCons)
thus "weight v (lhd Ps) ≠ None"
using ‹v = lnth (LCons v Ps) 0› A
by (metis ‹LCons v Ps = p› ‹Ps ≠ LNil› ‹∃p. Ps = p ∧ (∀i. enat (Suc i) < llength p ⟶ weight (lnth p i) (lnth p (Suc i)) ≠ None)› gen_llength_code(1) ldropn_0 ldropn_Suc_LCons ldropn_eq_LConsD llist.collapse(1) lnth_Suc_LCons not_lnull_conv)
qed
qed
qed
qed
qed
qed
text‹\subsubsection*{Energy Levels}
The energy level of a play is calculated by repeatedly updating the current energy according to the
edges in the play.
The final energy level of a finite play is ‹energy_level e p (the_enat (llength p -1))› where ‹e› is the initial energy.›
fun energy_level:: "'energy ⇒ 'position llist ⇒ nat ⇒ 'energy option" where
"energy_level e p 0 = (if p = LNil then None else Some e)" |
"energy_level e p (Suc i) =
(if (energy_level e p i) = None ∨ llength p ≤ (Suc i) then None
else apply_w (lnth p i)(lnth p (Suc i)) (the (energy_level e p i)))"
text‹We establish some (in)equalities to simplify later proofs.›
lemma energy_level_cons:
assumes "valid_play (LCons v Ps)" and "¬lnull Ps" and
"apply_w v (lhd Ps) e ≠ None" and "enat i < (llength Ps)"
shows "energy_level (the (apply_w v (lhd Ps) e)) Ps i
= energy_level e (LCons v Ps) (Suc i)"
using assms proof(induction i arbitrary: e Ps rule: energy_level.induct)
case (1 e p)
then show ?case using energy_level.simps
by (smt (verit) ldropn_Suc_LCons ldropn_eq_LNil le_zero_eq lhd_conv_lnth llength_eq_0 llist.distinct(1) lnth_0 lnth_Suc_LCons lnull_def option.collapse option.discI option.sel zero_enat_def)
next
case (2 e p n)
hence "enat n < (llength Ps)"
using Suc_ile_eq nless_le by blast
hence IA: "energy_level (the (apply_w v (lhd Ps) e)) Ps n = energy_level e (LCons v Ps) (Suc n)"
using 2 by simp
have "(llength Ps) > Suc n" using ‹enat (Suc n) < (llength Ps)›
by simp
hence "llength (LCons v Ps) > (Suc (Suc n))"
by (metis ldropn_Suc_LCons ldropn_eq_LNil linorder_not_less)
show "energy_level (the (apply_w v (lhd Ps) e)) Ps (Suc n) = energy_level e (LCons v Ps) (Suc (Suc n))"
proof(cases "energy_level e (LCons v Ps) (Suc (Suc n)) = None")
case True
hence "(energy_level e (LCons v Ps) (Suc n)) = None ∨ llength (LCons v Ps) ≤ (Suc (Suc n)) ∨ apply_w (lnth (LCons v Ps) (Suc n)) (lnth (LCons v Ps) (Suc (Suc n))) (the (energy_level e (LCons v Ps) (Suc n))) = None "
using energy_level.simps
by metis
hence none: "(energy_level e (LCons v Ps) (Suc n)) = None ∨ apply_w (lnth (LCons v Ps) (Suc n)) (lnth (LCons v Ps) (Suc (Suc n))) (the (energy_level e (LCons v Ps) (Suc n))) = None "
using ‹llength (LCons v Ps) > (Suc (Suc n))›
by (meson linorder_not_less)
show ?thesis
proof(cases "(energy_level e (LCons v Ps) (Suc n)) = None")
case True
then show ?thesis using IA by simp
next
case False
hence "apply_w (lnth (LCons v Ps) (Suc n)) (lnth (LCons v Ps) (Suc (Suc n))) (the (energy_level e (LCons v Ps) (Suc n))) = None "
using none by auto
hence "apply_w (lnth (LCons v Ps) (Suc n)) (lnth (LCons v Ps) (Suc (Suc n))) (the (energy_level (the (apply_w v (lhd Ps) e)) Ps n)) = None "
using IA by auto
then show ?thesis by (simp add: IA)
qed
next
case False
then show ?thesis using IA
by (smt (verit) ‹enat (Suc n) < llength Ps› energy_level.simps(2) lnth_Suc_LCons order.asym order_le_imp_less_or_eq)
qed
qed
lemma energy_level_nth:
assumes "energy_level e p m ≠ None" and "Suc i ≤ m"
shows "apply_w (lnth p i) (lnth p (Suc i)) (the (energy_level e p i)) ≠ None
∧ energy_level e p i ≠ None"
using assms proof(induct "m - (Suc i)" arbitrary: i)
case 0
then show ?case using energy_level.simps
by (metis diff_diff_cancel minus_nat.diff_0)
next
case (Suc x)
hence "x = m - Suc (Suc i)"
by (metis add_Suc_shift diff_add_inverse2 diff_le_self le_add_diff_inverse)
hence "apply_w (lnth p (Suc i)) (lnth p (Suc (Suc i))) (the (energy_level e p (Suc i))) ≠ None ∧ (energy_level e p (Suc i)) ≠ None" using Suc
by (metis diff_is_0_eq nat.distinct(1) not_less_eq_eq)
then show ?case using energy_level.simps by metis
qed
lemma energy_level_append:
assumes "lfinite p" and "i < the_enat (llength p)" and
"energy_level e p (the_enat (llength p) -1) ≠ None"
shows "energy_level e p i = energy_level e (lappend p p') i"
proof-
have A: "⋀i. i < the_enat (llength p) ⟹ energy_level e p i ≠ None" using energy_level_nth assms
by (metis Nat.lessE diff_Suc_1 less_eq_Suc_le)
show ?thesis using assms A proof(induct i)
case 0
then show ?case using energy_level.simps
by (metis LNil_eq_lappend_iff llength_lnull llist.disc(1) the_enat_0 verit_comp_simplify1(1))
next
case (Suc i)
hence "energy_level e p i = energy_level e (lappend p p') i"
by simp
have "Suc i < (llength p) ∧ energy_level e p i ≠ None" using Suc
by (metis Suc_lessD enat_ord_simps(2) lfinite_conv_llength_enat the_enat.simps)
hence "Suc i < (llength (lappend p p')) ∧ energy_level e (lappend p p') i ≠ None"
using ‹energy_level e p i = energy_level e (lappend p p') i›
by (metis dual_order.strict_trans1 enat_le_plus_same(1) llength_lappend)
then show ?case unfolding energy_level.simps using ‹Suc i < (llength p) ∧ energy_level e p i ≠ None› ‹energy_level e p i = energy_level e (lappend p p') i›
by (smt (verit) Suc_ile_eq energy_level.elims le_zero_eq linorder_not_less lnth_lappend1 nle_le the_enat.simps zero_enat_def)
qed
qed
text‹\subsubsection*{Won Plays}
All infinite plays are won by the defender. Further, the attacker is energy-bound and the defender
wins if the energy level becomes ‹None›. Finite plays with an energy level that is not ‹None› are won by
a player, if the other is stuck.›
abbreviation "deadend g ≡ (∀g'. weight g g' = None)"
abbreviation "attacker_stuck p ≡ (llast p)∈ attacker ∧ deadend (llast p)"
definition defender_wins_play:: "'energy ⇒ 'position llist ⇒ bool" where
"defender_wins_play e p ≡ lfinite p ⟶
(energy_level e p (the_enat (llength p)-1) = None ∨ attacker_stuck p)"
subsection‹Energy-positional Strategies›
text‹
Energy-positional strategies map pairs of energies and positions to a next position.
Further, we focus on attacker strategies, i.e.\ partial functions mapping attacker positions to successors.›
definition attacker_strategy:: "('energy ⇒ 'position ⇒ 'position option) ⇒ bool" where
"attacker_strategy s = (∀g e. (g ∈ attacker ∧ ¬ deadend g) ⟶
(s e g ≠ None ∧ weight g (the (s e g)) ≠ None))"
text‹We now define what it means for a play to be consistent with some strategy.›
coinductive play_consistent_attacker::"('energy ⇒ 'position ⇒ 'position option) ⇒ 'position llist ⇒ 'energy ⇒ bool" where
"play_consistent_attacker _ LNil _" |
"play_consistent_attacker _ (LCons v LNil) _" |
"⟦play_consistent_attacker s Ps (the (apply_w v (lhd Ps) e)); ¬lnull Ps;
v ∈ attacker ⟶ (s e v) = Some (lhd Ps)⟧
⟹ play_consistent_attacker s (LCons v Ps) e"
text‹The coinductive definition allows for coinduction.›
lemma play_consistent_attacker_coinduct:
assumes "Q s p e" and
"⋀s v Ps e'. Q s (LCons v Ps) e' ∧ ¬lnull Ps ⟹
Q s Ps (the (apply_w v (lhd Ps) e')) ∧
(v ∈ attacker ⟶ s e' v = Some (lhd Ps))"
shows "play_consistent_attacker s p e"
using assms proof(coinduction arbitrary: s p e)
case play_consistent_attacker
then show ?case
proof(cases "p = LNil")
case True
then show ?thesis by simp
next
case False
hence "∃ v Ps. p = LCons v Ps"
by (meson llist.exhaust)
from this obtain v Ps where "p = LCons v Ps" by auto
then show ?thesis
proof(cases "Ps = LNil")
case True
then show ?thesis using ‹p = LCons v Ps› by simp
next
case False
hence "Q s Ps (the (apply_w v (lhd Ps) e)) ∧ (v ∈ attacker ⟶ s e v = Some (lhd Ps))"
using assms
using ‹p = LCons v Ps› llist.collapse(1) play_consistent_attacker(1) by blast
then show ?thesis using play_consistent_attacker play_consistent_attacker.simps
by (metis (no_types, lifting) ‹p = LCons v Ps› lnull_def)
qed
qed
qed
text‹Adding a position to the beginning of a consistent play is simple by definition.
It is harder to see, when a position can be added to the end of a finite play. For this we introduce the following lemma.›
lemma play_consistent_attacker_append_one:
assumes "play_consistent_attacker s p e" and "lfinite p" and
"energy_level e p (the_enat (llength p)-1) ≠ None" and
"valid_play (lappend p (LCons g LNil))" and "llast p ∈ attacker ⟶
Some g = s (the (energy_level e p (the_enat (llength p)-1))) (llast p)"
shows "play_consistent_attacker s (lappend p (LCons g LNil)) e"
using assms proof(induct "the_enat (llength p)" arbitrary: p e)
case 0
then show ?case
by (metis lappend_lnull1 length_list_of length_list_of_conv_the_enat llength_eq_0 play_consistent_attacker.simps zero_enat_def)
next
case (Suc x)
hence "∃v Ps. p = LCons v Ps"
by (metis Zero_not_Suc llength_LNil llist.exhaust the_enat_0)
from this obtain v Ps where "p = LCons v Ps" by auto
have B: "play_consistent_attacker s (lappend Ps (LCons g LNil)) (the (apply_w v (lhd (lappend Ps (LCons g LNil)))e))"
proof(cases "Ps=LNil")
case True
then show ?thesis
by (simp add: play_consistent_attacker.intros(2))
next
case False
show ?thesis
proof(rule Suc.hyps)
show "valid_play (lappend Ps (LCons g LNil))"
by (metis (no_types, lifting) LNil_eq_lappend_iff Suc.prems(4) ‹p = LCons v Ps› lappend_code(2) llist.distinct(1) llist.inject valid_play.cases)
show "x = the_enat (llength Ps)" using Suc ‹p = LCons v Ps›
by (metis diff_add_inverse length_Cons length_list_of_conv_the_enat lfinite_ltl list_of_LCons ltl_simps(2) plus_1_eq_Suc)
show "play_consistent_attacker s Ps (the (apply_w v (lhd (lappend Ps (LCons g LNil))) e))"
using False Suc.prems(1) ‹p = LCons v Ps› play_consistent_attacker.cases by fastforce
show "lfinite Ps" using Suc ‹p = LCons v Ps› by simp
hence EL: "energy_level (the (apply_w v (lhd (lappend Ps (LCons g LNil))) e)) Ps
(the_enat (llength Ps) - 1) = energy_level e (LCons v (lappend Ps (LCons g LNil)))
(Suc (the_enat (llength Ps) - 1))"
proof-
have A: "valid_play (LCons v Ps) ∧ ¬ lnull Ps ∧ apply_w v (lhd Ps) e ≠ None ∧
enat (the_enat (llength Ps) - 1) < llength Ps"
proof
show "valid_play (LCons v Ps)" proof(rule valid_play_nth)
fix i
show "enat (Suc i) < llength (LCons v Ps) ⟶
weight (lnth (LCons v Ps) i) (lnth (LCons v Ps) (Suc i)) ≠ None "
proof
assume "enat (Suc i) < llength (LCons v Ps)"
hence "(lnth (LCons v Ps) i) = (lnth (lappend p (LCons g LNil)) i)" using ‹p = LCons v Ps›
by (metis Suc_ile_eq lnth_lappend1 order.strict_implies_order)
have "(lnth (LCons v Ps) (Suc i)) = (lnth (lappend p (LCons g LNil)) (Suc i))" using ‹p = LCons v Ps› ‹enat (Suc i) < llength (LCons v Ps)›
by (metis lnth_lappend1)
from Suc have "valid_play (lappend p (LCons g LNil))" by simp
hence "weight (lnth (lappend p (LCons g LNil)) i) (lnth (lappend p (LCons g LNil)) (Suc i)) ≠ None"
using ‹enat (Suc i) < llength (LCons v Ps)› valid_play_nth_not_None
by (metis Suc.prems(2) ‹p = LCons v Ps› llist.disc(2) lstrict_prefix_lappend_conv lstrict_prefix_llength_less min.absorb4 min.strict_coboundedI1)
thus "weight (lnth (LCons v Ps) i) (lnth (LCons v Ps) (Suc i)) ≠ None"
using ‹(lnth (LCons v Ps) (Suc i)) = (lnth (lappend p (LCons g LNil)) (Suc i))› ‹(lnth (LCons v Ps) i) = (lnth (lappend p (LCons g LNil)) i)› by simp
qed
qed
show "¬ lnull Ps ∧ apply_w v (lhd Ps) e ≠ None ∧ enat (the_enat (llength Ps) - 1) < llength Ps"
proof
show "¬ lnull Ps" using False by auto
show "apply_w v (lhd Ps) e ≠ None ∧ enat (the_enat (llength Ps) - 1) < llength Ps"
proof
show "apply_w v (lhd Ps) e ≠ None" using Suc
by (smt (verit, ccfv_threshold) One_nat_def ‹¬ lnull Ps› ‹lfinite Ps› ‹p = LCons v Ps› ‹x = the_enat (llength Ps)› diff_add_inverse energy_level.simps(1) energy_level_nth le_SucE le_add1 length_list_of length_list_of_conv_the_enat lhd_conv_lnth llength_eq_0 llist.discI(2) lnth_0 lnth_ltl ltl_simps(2) option.sel plus_1_eq_Suc zero_enat_def)
show "enat (the_enat (llength Ps) - 1) < llength Ps" using False
by (metis ‹¬ lnull Ps› ‹lfinite Ps› diff_Suc_1 enat_0_iff(2) enat_ord_simps(2) gr0_conv_Suc lessI lfinite_llength_enat llength_eq_0 not_gr_zero the_enat.simps)
qed
qed
qed
have "energy_level (the (apply_w v (lhd (lappend Ps (LCons g LNil))) e)) Ps
(the_enat (llength Ps) - 1) = energy_level (the (apply_w v (lhd Ps) e)) Ps
(the_enat (llength Ps) - 1)" using False
by (simp add: lnull_def)
also have "... = energy_level e (LCons v Ps) (Suc (the_enat (llength Ps) - 1))"
using energy_level_cons A by simp
also have "... = energy_level e (LCons v (lappend Ps (LCons g LNil)))
(Suc (the_enat (llength Ps) - 1))" using energy_level_append
by (metis False One_nat_def Suc.hyps(2) Suc.prems(2) Suc.prems(3) ‹lfinite Ps› ‹p = LCons v Ps› ‹x = the_enat (llength Ps)› diff_Suc_less lappend_code(2) length_list_of length_list_of_conv_the_enat less_SucE less_Suc_eq_0_disj llength_eq_0 llist.disc(1) llist.expand nat_add_left_cancel_less plus_1_eq_Suc zero_enat_def)
finally show ?thesis .
qed
thus EL_notNone: "energy_level (the (apply_w v (lhd (lappend Ps (LCons g LNil))) e)) Ps
(the_enat (llength Ps) - 1) ≠ None"
using Suc
by (metis False One_nat_def Suc_pred ‹p = LCons v Ps› ‹x = the_enat (llength Ps)› diff_Suc_1' energy_level.simps(1) energy_level_append lappend_code(2) lessI not_less_less_Suc_eq not_one_less_zero option.distinct(1) zero_less_Suc zero_less_diff)
show "llast Ps ∈ attacker ⟶
Some g = s (the (energy_level (the (apply_w v (lhd (lappend Ps (LCons g LNil))) e)) Ps
(the_enat (llength Ps) - 1)))(llast Ps)"
proof
assume "llast Ps ∈ attacker"
have "llast Ps = llast p" using False ‹p = LCons v Ps›
by (simp add: llast_LCons lnull_def)
hence "llast p ∈ attacker" using ‹llast Ps ∈ attacker› by simp
hence "Some g = s (the (energy_level e p (the_enat (llength p) - 1))) (llast p)" using Suc by simp
hence "Some g = s (the (energy_level e (LCons v Ps) (the_enat (llength (LCons v Ps)) - 1))) (llast Ps)" using ‹p = LCons v Ps› ‹llast Ps = llast p› by simp
have "apply_w v (lhd Ps) e ≠ None" using Suc
by (smt (verit, best) EL EL_notNone False One_nat_def energy_level.simps(1) energy_level_nth le_add1 lhd_conv_lnth lhd_lappend llist.discI(2) llist.exhaust_sel lnth_0 lnth_Suc_LCons lnull_lappend option.sel plus_1_eq_Suc)
thus "Some g = s (the (energy_level (the (apply_w v (lhd (lappend Ps (LCons g LNil))) e)) Ps
(the_enat (llength Ps) - 1)))(llast Ps)" using EL
by (metis (no_types, lifting) False Suc.hyps(2) Suc.prems(2) Suc.prems(3) Suc_diff_Suc ‹Some g = s (the (energy_level e (LCons v Ps) (the_enat (llength (LCons v Ps)) - 1))) (llast Ps)› ‹lfinite Ps› ‹p = LCons v Ps› ‹x = the_enat (llength Ps)› cancel_comm_monoid_add_class.diff_cancel diff_Suc_1 energy_level_append lappend_code(2) lessI lfinite.cases lfinite_conv_llength_enat linorder_neqE_nat llength_eq_0 llist.discI(2) not_add_less1 plus_1_eq_Suc the_enat.simps zero_enat_def)
qed
qed
qed
have A: "¬ lnull (lappend Ps (LCons g LNil)) ∧ (v ∈ attacker ⟶ (s e v = Some (lhd (lappend Ps (LCons g LNil)))))"
proof
show "¬ lnull (lappend Ps (LCons g LNil))" by simp
show "v ∈ attacker ⟶
s e v = Some (lhd (lappend Ps (LCons g LNil)))"
proof
assume "v ∈ attacker"
show "s e v = Some (lhd (lappend Ps (LCons g LNil)))" using ‹v ∈ attacker› Suc
by (smt (verit) One_nat_def ‹p = LCons v Ps› diff_add_0 energy_game.energy_level.simps(1) eq_LConsD length_Cons length_list_of_conv_the_enat lfinite_ltl lhd_lappend list.size(3) list_of_LCons list_of_LNil llast_singleton llist.disc(1) option.exhaust_sel option.inject play_consistent_attacker.cases plus_1_eq_Suc)
qed
qed
have "(lappend p (LCons g LNil)) = LCons v (lappend Ps (LCons g LNil))"
by (simp add: ‹p = LCons v Ps›)
thus ?case using play_consistent_attacker.simps A B
by meson
qed
text‹We now define attacker winning strategies, i.e.\ attacker strategies where the defender does not win any consistent plays w.r.t\ some initial energy and a starting position.›
fun attacker_winning_strategy:: "('energy ⇒ 'position ⇒ 'position option) ⇒ 'energy ⇒ 'position ⇒ bool" where
"attacker_winning_strategy s e g = (attacker_strategy s ∧
(∀p. (play_consistent_attacker s (LCons g p) e ∧ valid_play (LCons g p))
⟶ ¬defender_wins_play e (LCons g p)))"
subsection‹Non-positional Strategies›
text‹A non-positional strategy maps finite plays to a next position. We now introduce non-positional strategies to better characterise attacker winning budgets.
These definitions closely resemble the definitions for energy-positional strategies.›
definition attacker_nonpos_strategy:: "('position list ⇒ 'position option) ⇒ bool" where
"attacker_nonpos_strategy s = (∀list ≠ []. ((last list) ∈ attacker
∧ ¬deadend (last list)) ⟶ s list ≠ None
∧ (weight (last list) (the (s list)))≠None)"
text‹We now define what it means for a play to be consistent with some non-positional strategy.›
coinductive play_consistent_attacker_nonpos::"('position list ⇒ 'position option) ⇒ ('position llist) ⇒ ('position list) ⇒ bool" where
"play_consistent_attacker_nonpos s LNil _" |
"play_consistent_attacker_nonpos s (LCons v LNil) []" |
"(last (w#l))∉attacker
⟹ play_consistent_attacker_nonpos s (LCons v LNil) (w#l)" |
"⟦(last (w#l))∈attacker; the (s (w#l)) = v ⟧
⟹ play_consistent_attacker_nonpos s (LCons v LNil) (w#l)" |
"⟦play_consistent_attacker_nonpos s Ps (l@[v]); ¬lnull Ps; v∉attacker⟧
⟹ play_consistent_attacker_nonpos s (LCons v Ps) l" |
"⟦play_consistent_attacker_nonpos s Ps (l@[v]); ¬lnull Ps; v∈attacker;
lhd Ps = the (s (l@[v]))⟧
⟹ play_consistent_attacker_nonpos s (LCons v Ps) l"
inductive_simps play_consistent_attacker_nonpos_cons_simp:
"play_consistent_attacker_nonpos s (LCons x xs) []"
text‹The definition allows for coinduction.›
lemma play_consistent_attacker_nonpos_coinduct:
assumes "Q s p l" and
base: "⋀s v l. Q s (LCons v LNil) l ⟹ (l = [] ∨ (last l) ∉ attacker
∨ ((last l)∈attacker ∧ the (s l) = v))" and
step: "⋀s v Ps l. Q s (LCons v Ps) l ∧ Ps≠LNil
⟹ Q s Ps (l@[v]) ∧ (v∈attacker ⟶ lhd Ps = the (s (l@[v])))"
shows "play_consistent_attacker_nonpos s p l"
using assms proof(coinduction arbitrary: s p l)
case play_consistent_attacker_nonpos
then show ?case proof(cases "p=LNil")
case True
then show ?thesis by simp
next
case False
hence "∃v p'. p = LCons v p'"
by (simp add: neq_LNil_conv)
from this obtain v p' where "p=LCons v p'" by auto
then show ?thesis proof(cases "p'=LNil")
case True
then show ?thesis
by (metis ‹p = LCons v p'› neq_Nil_conv play_consistent_attacker_nonpos(1) play_consistent_attacker_nonpos(2))
next
case False
then show ?thesis
using ‹p = LCons v p'› assms(3) llist.expand play_consistent_attacker_nonpos(1) assms(2) by auto
qed
qed
qed
text‹We now show that a position can be added to the end of a finite consitent play while remaining consistent.›
lemma consistent_nonpos_append_defender:
assumes "play_consistent_attacker_nonpos s (LCons v Ps) l" and
"llast (LCons v Ps) ∉ attacker" and "lfinite (LCons v Ps)"
shows "play_consistent_attacker_nonpos s (lappend (LCons v Ps) (LCons g' LNil)) l"
using assms proof(induction "list_of Ps" arbitrary: v Ps l)
case Nil
hence v_append_Ps: "play_consistent_attacker_nonpos s (lappend (LCons v Ps) (LCons g' LNil)) l = play_consistent_attacker_nonpos s (LCons v (LCons g' LNil)) l"
by (metis lappend_code(1) lappend_code(2) lfinite_LCons llist_of_eq_LNil_conv llist_of_list_of)
from Nil.prems(1) have "play_consistent_attacker_nonpos s (LCons g' LNil) (l@[v])" using play_consistent_attacker_nonpos.intros Nil
by (metis (no_types, lifting) lfinite_LCons list.exhaust_sel llast_singleton llist_of.simps(1) llist_of_list_of snoc_eq_iff_butlast)
hence "play_consistent_attacker_nonpos s (LCons v (LCons g' LNil)) l" using play_consistent_attacker_nonpos.intros Nil
by (metis lfinite_code(2) llast_singleton llist.disc(2) llist_of.simps(1) llist_of_list_of)
then show ?case using v_append_Ps by simp
next
case (Cons a x)
hence v_append_Ps: "play_consistent_attacker_nonpos s (lappend (LCons v Ps) (LCons g' LNil)) l = play_consistent_attacker_nonpos s (LCons v (lappend Ps (LCons g' LNil))) l"
by simp
from Cons have "¬lnull Ps"
by (metis list.discI list_of_LNil llist.collapse(1))
have "¬ lnull (lappend Ps (LCons g' LNil))" by simp
have "x = list_of (ltl Ps)" using Cons.hyps(2)
by (metis Cons.prems(3) lfinite_code(2) list.sel(3) tl_list_of)
have "llast (LCons (lhd Ps) (ltl Ps)) ∉ attacker" using Cons.prems(2)
by (simp add: ‹¬ lnull Ps› llast_LCons)
have "lfinite (LCons (lhd Ps) (ltl Ps))" using Cons.prems(3) by simp
have "play_consistent_attacker_nonpos s (LCons (lhd Ps) (ltl Ps)) (l @ [v])" using Cons.prems(1) play_consistent_attacker_nonpos.simps
by (smt (verit, best) ‹¬ lnull Ps› eq_LConsD lhd_LCons lhd_LCons_ltl ltl_simps(2))
hence "play_consistent_attacker_nonpos s (lappend Ps (LCons g' LNil)) (l @ [v])" using Cons.hyps ‹lfinite (LCons (lhd Ps) (ltl Ps))› ‹llast (LCons (lhd Ps) (ltl Ps)) ∉ attacker› ‹x = list_of (ltl Ps)›
by (metis ‹¬ lnull Ps› lhd_LCons_ltl)
have "play_consistent_attacker_nonpos s (LCons v (lappend Ps (LCons g' LNil))) l"
proof(cases "v ∈ attacker")
case True
have "lhd Ps = the (s (l @ [v]))" using True Cons.prems(1) play_consistent_attacker_nonpos.simps
by (smt (verit) ‹¬ lnull Ps› llist.distinct(1) llist.inject lnull_def)
hence "lhd (lappend Ps (LCons g' LNil)) = the (s (l @ [v]))" by (simp add: ‹¬ lnull Ps›)
then show ?thesis using play_consistent_attacker_nonpos.intros(6) True ‹play_consistent_attacker_nonpos s (lappend Ps (LCons g' LNil)) (l @ [v])› ‹lhd (lappend Ps (LCons g' LNil)) = the (s (l @ [v]))› ‹¬ lnull (lappend Ps (LCons g' LNil))›
by simp
next
case False
then show ?thesis using play_consistent_attacker_nonpos.intros(5) False ‹¬ lnull (lappend Ps (LCons g' LNil))› ‹play_consistent_attacker_nonpos s (lappend Ps (LCons g' LNil)) (l @ [v])›
by simp
qed
then show ?case using v_append_Ps by simp
qed
lemma consistent_nonpos_append_attacker:
assumes "play_consistent_attacker_nonpos s (LCons v Ps) l"
and "llast (LCons v Ps) ∈ attacker" and "lfinite (LCons v Ps)"
shows "play_consistent_attacker_nonpos s (lappend (LCons v Ps) (LCons (the (s (l@(list_of (LCons v Ps))))) LNil)) l"
using assms proof(induction "list_of Ps" arbitrary: v Ps l)
case Nil
hence v_append_Ps: "play_consistent_attacker_nonpos s (lappend (LCons v Ps) (LCons (the (s (l@(list_of (LCons v Ps))))) LNil)) l
= play_consistent_attacker_nonpos s (LCons v (LCons (the (s (l@[v]))) LNil)) l"
by (metis lappend_code(1) lappend_code(2) lfinite_code(2) list_of_LCons llist_of.simps(1) llist_of_list_of)
have "play_consistent_attacker_nonpos s (LCons v (LCons (the (s (l@[v]))) LNil)) l" using play_consistent_attacker_nonpos.intros Nil
by (metis hd_Cons_tl lhd_LCons llist.disc(2))
then show ?case using v_append_Ps by simp
next
case (Cons a x)
have v_append_Ps: "play_consistent_attacker_nonpos s (lappend (LCons v Ps) (LCons (the (s (l @ list_of (LCons v Ps)))) LNil)) l
= play_consistent_attacker_nonpos s (LCons v (lappend Ps (LCons (the (s (l @ [v]@list_of Ps))) LNil))) l"
using Cons.prems(3) by auto
have "x = list_of (ltl Ps)" using Cons.hyps(2)
by (metis Cons.prems(3) lfinite_code(2) list.sel(3) tl_list_of)
have "play_consistent_attacker_nonpos s (LCons (lhd Ps) (ltl Ps)) (l@[v])" using Cons.prems(1) play_consistent_attacker_nonpos.simps
by (smt (verit) Cons.hyps(2) eq_LConsD lhd_LCons list.discI list_of_LNil ltl_simps(2))
have "llast (LCons (lhd Ps) (ltl Ps)) ∈ attacker" using Cons.prems(2)
by (metis Cons.hyps(2) lhd_LCons_ltl list.distinct(1) list_of_LNil llast_LCons llist.collapse(1))
have "lfinite (LCons (lhd Ps) (ltl Ps))" using Cons.prems(3) by simp
hence "play_consistent_attacker_nonpos s (lappend Ps (LCons (the (s ((l @[v])@list_of Ps))) LNil)) (l@[v])"
using Cons.hyps ‹x = list_of (ltl Ps)› ‹play_consistent_attacker_nonpos s (LCons (lhd Ps) (ltl Ps)) (l@[v])›
‹llast (LCons (lhd Ps) (ltl Ps)) ∈ attacker›
by (metis llist.exhaust_sel ltl_simps(1) not_Cons_self2)
hence "play_consistent_attacker_nonpos s (LCons v (lappend Ps (LCons (the (s ((l @[v])@(list_of Ps)))) LNil))) l"
using play_consistent_attacker_nonpos.simps Cons
by (smt (verit) lhd_LCons lhd_lappend list.discI list_of_LNil llist.distinct(1) lnull_lappend ltl_simps(2))
then show ?case using v_append_Ps by simp
qed
text‹We now define non-positional attacker winning strategies, i.e. attacker strategies where the defender
does not win any consistent plays w.r.t some initial energy and a starting position.›
fun nonpos_attacker_winning_strategy:: "('position list ⇒ 'position option) ⇒
'energy ⇒ 'position ⇒ bool" where
"nonpos_attacker_winning_strategy s e g = (attacker_nonpos_strategy s ∧
(∀p. (play_consistent_attacker_nonpos s (LCons g p) []
∧ valid_play (LCons g p)) ⟶ ¬defender_wins_play e (LCons g p)))"
subsection‹Attacker Winning Budgets›
text‹We now define attacker winning budgets utilising strategies.›
fun winning_budget:: "'energy ⇒ 'position ⇒ bool" where
"winning_budget e g = (∃s. attacker_winning_strategy s e g)"
fun nonpos_winning_budget:: "'energy ⇒ 'position ⇒ bool" where
"nonpos_winning_budget e g = (∃s. nonpos_attacker_winning_strategy s e g)"
text‹Note that ‹nonpos_winning_budget = winning_budget› holds but is not proven in this theory.
Using this fact we can give an inductive characterisation of attacker winning budgets.
›
inductive winning_budget_ind:: "'energy ⇒ 'position ⇒ bool" where
defender: "winning_budget_ind e g" if
"g ∉ attacker ∧ (∀g'. weight g g' ≠ None ⟶ (apply_w g g' e≠ None
∧ winning_budget_ind (the (apply_w g g' e)) g'))" |
attacker: "winning_budget_ind e g" if
"g ∈ attacker ∧ (∃g'. weight g g' ≠ None ∧ apply_w g g' e≠ None
∧ winning_budget_ind (the (apply_w g g' e)) g')"
text‹Before proving some correspondence of those definitions we first note that attacker winning budgets
in monotonic energy games are upward-closed. We show this for two of the three definitions.›
lemma upward_closure_wb_nonpos:
assumes monotonic: "⋀g g' e e'. weight g g' ≠ None
⟹ apply_w g g' e ≠ None ⟹ leq e e' ⟹ apply_w g g' e' ≠ None
∧ leq (the (apply_w g g' e)) (the (apply_w g g' e'))"
and "leq e e'" and "nonpos_winning_budget e g"
shows "nonpos_winning_budget e' g"
proof-
from assms have "∃s. nonpos_attacker_winning_strategy s e g" using nonpos_winning_budget.simps by simp
from this obtain s where S: "nonpos_attacker_winning_strategy s e g" by auto
have "nonpos_attacker_winning_strategy s e' g" unfolding nonpos_attacker_winning_strategy.simps
proof
show "attacker_nonpos_strategy s" using S by simp
show "∀p. play_consistent_attacker_nonpos s (LCons g p) [] ∧ valid_play (LCons g p) ⟶ ¬ defender_wins_play e' (LCons g p)"
proof
fix p
show "play_consistent_attacker_nonpos s (LCons g p) [] ∧ valid_play (LCons g p) ⟶ ¬ defender_wins_play e' (LCons g p) "
proof
assume P: "play_consistent_attacker_nonpos s (LCons g p) [] ∧ valid_play (LCons g p)"
hence X: "lfinite (LCons g p) ∧ ¬ (energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) = None ∨ llast (LCons g p) ∈ attacker ∧ deadend (llast (LCons g p)))"
using S unfolding nonpos_attacker_winning_strategy.simps defender_wins_play_def by simp
have "lfinite (LCons g p) ∧ ¬ (energy_level e' (LCons g p) (the_enat (llength (LCons g p)) - 1) = None ∨ llast (LCons g p) ∈ attacker ∧ deadend (llast (LCons g p)))"
proof
show "lfinite (LCons g p)" using P S unfolding nonpos_attacker_winning_strategy.simps defender_wins_play_def by simp
have "energy_level e' (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None ∧ ¬(llast (LCons g p) ∈ attacker ∧ deadend (llast (LCons g p)))"
proof
have E: "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None" using P S unfolding nonpos_attacker_winning_strategy.simps defender_wins_play_def by simp
have "⋀len. len ≤ the_enat (llength (LCons g p)) - 1 ⟶ energy_level e' (LCons g p) len ≠ None ∧ (leq (the (energy_level e (LCons g p) len)) (the (energy_level e' (LCons g p) len)))"
proof
fix len
show "len ≤ the_enat (llength (LCons g p)) - 1 ⟹ energy_level e' (LCons g p) len ≠ None ∧ leq (the (energy_level e (LCons g p) len)) (the (energy_level e' (LCons g p) len))"
proof(induct len)
case 0
then show ?case using energy_level.simps assms(2)
by (simp add: llist.distinct(1) option.discI option.sel)
next
case (Suc len)
hence "energy_level e' (LCons g p) len ≠ None" by simp
have W: "weight (lnth (LCons g p) len)(lnth (LCons g p) (Suc len)) ≠ None" using P Suc.prems valid_play.simps valid_play_nth_not_None
by (smt (verit) ‹lfinite (LCons g p)› diff_Suc_1 enat_ord_simps(2) le_less_Suc_eq less_imp_diff_less lfinite_llength_enat linorder_le_less_linear not_less_eq the_enat.simps)
have A: "apply_w (lnth (LCons g p) len) (lnth (LCons g p) (Suc len)) (the (energy_level e (LCons g p) len)) ≠ None"
using E Suc.prems energy_level_nth by blast
have "llength (LCons g p) > Suc len" using Suc.prems
by (metis ‹lfinite (LCons g p)› diff_Suc_1 enat_ord_simps(2) less_imp_diff_less lfinite_conv_llength_enat nless_le not_le_imp_less not_less_eq the_enat.simps)
hence "energy_level e' (LCons g p) (Suc len) = apply_w (lnth (LCons g p) len)(lnth (LCons g p) (Suc len)) (the (energy_level e' (LCons g p) len))"
using ‹energy_level e' (LCons g p) len ≠ None› energy_level.simps
by (meson leD)
then show ?case using A W Suc assms
by (smt (verit) E Suc_leD energy_level.simps(2) energy_level_nth)
qed
qed
thus "energy_level e' (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None" by simp
show " ¬ (llast (LCons g p) ∈ attacker ∧ deadend (llast (LCons g p)))" using P S unfolding nonpos_attacker_winning_strategy.simps defender_wins_play_def by simp
qed
thus "¬ (energy_level e' (LCons g p) (the_enat (llength (LCons g p)) - 1) = None ∨ llast (LCons g p) ∈ attacker ∧ deadend (llast (LCons g p)))"
by simp
qed
thus "¬ defender_wins_play e' (LCons g p)" unfolding defender_wins_play_def by simp
qed
qed
qed
thus ?thesis using nonpos_winning_budget.simps by auto
qed
lemma upward_closure_wb_ind:
assumes monotonic: "⋀g g' e e'. weight g g' ≠ None
⟹ apply_w g g' e ≠ None ⟹ leq e e' ⟹ apply_w g g' e' ≠ None
∧ leq (the (apply_w g g' e)) (the (apply_w g g' e'))"
and "leq e e'" and "winning_budget_ind e g"
shows "winning_budget_ind e' g"
proof-
define P where "P ≡ λ e g. (∀e'. leq e e' ⟶ winning_budget_ind e' g)"
have "P e g" using assms(3) proof (induct rule: winning_budget_ind.induct)
case (defender g e)
then show ?case using P_def
using monotonic winning_budget_ind.defender by blast
next
case (attacker g e)
then show ?case using P_def
using monotonic winning_budget_ind.attacker by blast
qed
thus ?thesis using assms(2) P_def by blast
qed
text‹Now we prepare the proof of the inductive characterisation. For this we define an order and a set allowing for a well-founded induction.›
definition strategy_order:: "('energy ⇒ 'position ⇒ 'position option) ⇒
'position × 'energy ⇒ 'position × 'energy ⇒ bool" where
"strategy_order s ≡ λ(g1, e1)(g2, e2).Some e1 = apply_w g2 g1 e2 ∧
(if g2 ∈ attacker then Some g1 = s e2 g2 else weight g2 g1 ≠ None)"
definition reachable_positions:: "('energy ⇒ 'position ⇒ 'position option) ⇒ 'position ⇒ 'energy ⇒ ('position × 'energy) set" where
"reachable_positions s g e = {(g',e')| g' e'.
(∃p. lfinite p ∧ llast (LCons g p) = g' ∧ valid_play (LCons g p)
∧ play_consistent_attacker s (LCons g p) e
∧ Some e' = energy_level e (LCons g p) (the_enat (llength p)))}"
lemma strategy_order_well_founded:
assumes "attacker_winning_strategy s e g"
shows "wfp_on (strategy_order s) (reachable_positions s g e)"
unfolding Restricted_Predicates.wfp_on_def
proof
assume "∃f. ∀i. f i ∈ reachable_positions s g e ∧ strategy_order s (f (Suc i)) (f i)"
from this obtain f where F: "∀i. f i ∈ reachable_positions s g e ∧ strategy_order s (f (Suc i)) (f i)" by auto
define p where "p = lmap (λi. fst (f i))(iterates Suc 0)"
hence "⋀i. lnth p i = fst (f i)"
by simp
from p_def have "¬lfinite p" by simp
have "⋀i. enat (Suc i) < llength p ⟹ weight (lnth p i) (lnth p (Suc i)) ≠ None"
proof-
fix i
have "∃g1 e1 g2 e2. (f i) = (g2, e2) ∧ f (Suc i) = (g1, e1)" using F reachable_positions_def by simp
from this obtain g1 e1 g2 e2 where "(f i) = (g2, e2)" and "f (Suc i) = (g1, e1)"
by blast
assume "enat (Suc i) < llength p"
have "weight g2 g1 ≠ None"
proof(cases "g2 ∈ attacker")
case True
then show ?thesis
proof(cases "deadend g2")
case True
have "(g2, e2) ∈ reachable_positions s g e" using F by (metis ‹f i = (g2, e2)›)
hence "(∃p'. (lfinite p' ∧ llast (LCons g p') = g2
∧ valid_play (LCons g p')
∧ play_consistent_attacker s (LCons g p') e)
∧ (Some e2 = energy_level e (LCons g p') (the_enat (llength p'))))"
using reachable_positions_def by simp
from this obtain p' where P': "(lfinite p' ∧ llast (LCons g p') = g2
∧ valid_play (LCons g p')
∧ play_consistent_attacker s (LCons g p') e)
∧ (Some e2 = energy_level e (LCons g p') (the_enat (llength p')))" by auto
have "¬defender_wins_play e (LCons g p')" using assms unfolding attacker_winning_strategy.simps using P' by auto
have "llast (LCons g p') ∈ attacker ∧ deadend (llast (LCons g p'))" using True ‹g2 ∈ attacker› P' by simp
hence "defender_wins_play e (LCons g p')"
unfolding defender_wins_play_def by simp
hence "False" using ‹¬defender_wins_play e (LCons g p')› by simp
then show ?thesis by simp
next
case False
from True have "Some g1 = s e2 g2"
using F unfolding strategy_order_def using ‹f (Suc i) = (g1, e1)› ‹(f i) = (g2, e2)›
by (metis (mono_tags, lifting) case_prod_conv)
have "(∀g e. (g ∈ attacker ∧ ¬ deadend g) ⟶ (s e g ≠ None ∧ weight g (the (s e g)) ≠ None))"
using assms unfolding attacker_winning_strategy.simps attacker_strategy_def
by simp
hence "weight g2 (the (s e2 g2)) ≠ None" using False True
by simp
then show ?thesis using ‹Some g1 = s e2 g2›
by (metis option.sel)
qed
next
case False
then show ?thesis using F unfolding strategy_order_def using ‹f (Suc i) = (g1, e1)› ‹(f i) = (g2, e2)›
by (metis (mono_tags, lifting) case_prod_conv)
qed
thus "weight (lnth p i) (lnth p (Suc i)) ≠ None"
using p_def ‹f i = (g2, e2)› ‹f (Suc i) = (g1, e1)› by simp
qed
hence "valid_play p" using valid_play_nth
by simp
have "(f 0) ∈ reachable_positions s g e" using F by simp
hence "∃g0 e0. f 0 = (g0,e0)" using reachable_positions_def by simp
from this obtain g0 e0 where "f 0 = (g0,e0)" by blast
hence "∃p'. (lfinite p' ∧ llast (LCons g p') = g0
∧ valid_play (LCons g p')
∧ play_consistent_attacker s (LCons g p') e)
∧ (Some e0 = energy_level e (LCons g p') (the_enat (llength p')))"
using ‹(f 0) ∈ reachable_positions s g e› unfolding reachable_positions_def by auto
from this obtain p' where P': "(lfinite p' ∧ llast (LCons g p') = g0
∧ valid_play (LCons g p')
∧ play_consistent_attacker s (LCons g p') e)
∧ (Some e0 = energy_level e (LCons g p') (the_enat (llength p')))" by auto
have "⋀i. strategy_order s (f (Suc i)) (f i)" using F by simp
hence "⋀i. Some (snd (f (Suc i))) = apply_w (fst (f i)) (fst (f (Suc i))) (snd (f i))" using strategy_order_def
by (simp add: case_prod_beta)
hence "⋀i. (snd (f (Suc i))) = the (apply_w (fst (f i)) (fst (f (Suc i))) (snd (f i)))"
by (metis option.sel)
have "⋀i. (energy_level e0 p i) = Some (snd (f i))"
proof-
fix i
show "(energy_level e0 p i) = Some (snd (f i))"
proof(induct i)
case 0
then show ?case using ‹f 0 = (g0,e0)› ‹¬ lfinite p› by auto
next
case (Suc i)
have "Some (snd (f (Suc i))) = (apply_w (fst (f i)) (fst (f (Suc i))) (snd (f i)))"
using ‹⋀i. Some (snd (f (Suc i))) = apply_w (fst (f i)) (fst (f (Suc i))) (snd (f i))› by simp
also have "... = (apply_w (fst (f i)) (fst (f (Suc i))) ( the (energy_level e0 p i)))" using Suc by simp
also have "... = (apply_w (lnth p i) (lnth p (Suc i)) ( the (energy_level e0 p i)))" using ‹⋀i. lnth p i = fst (f i)› by simp
also have "... = (energy_level e0 p (Suc i))" using energy_level.simps ‹¬ lfinite p› Suc
by (simp add: lfinite_conv_llength_enat)
finally show ?case
by simp
qed
qed
define Q where "Q ≡ λ s p e0. ¬lfinite p ∧ valid_play p ∧ (∀i. (energy_level e0 p i) ≠ None ∧ ((lnth p i), the (energy_level e0 p i)) ∈ reachable_positions s g e
∧ strategy_order s ((lnth p (Suc i)), the (energy_level e0 p (Suc i))) ((lnth p i), the (energy_level e0 p i)))"
have Q: "¬lfinite p ∧ valid_play p ∧ (∀i. (energy_level e0 p i) ≠ None ∧ ((lnth p i), the (energy_level e0 p i)) ∈ reachable_positions s g e
∧ strategy_order s ((lnth p (Suc i)), the (energy_level e0 p (Suc i))) ((lnth p i), the (energy_level e0 p i)))"
proof
show "¬ lfinite p " using ‹¬lfinite p› .
show "valid_play p ∧
(∀i. energy_level e0 p i ≠ None ∧
(lnth p i, the (energy_level e0 p i)) ∈ reachable_positions s g e ∧
strategy_order s (lnth p (Suc i), the (energy_level e0 p (Suc i)))
(lnth p i, the (energy_level e0 p i)))"
proof
show "valid_play p" using ‹valid_play p› .
show "∀i. energy_level e0 p i ≠ None ∧
(lnth p i, the (energy_level e0 p i)) ∈ reachable_positions s g e ∧
strategy_order s (lnth p (Suc i), the (energy_level e0 p (Suc i)))
(lnth p i, the (energy_level e0 p i)) "
proof
fix i
show "energy_level e0 p i ≠ None ∧
(lnth p i, the (energy_level e0 p i)) ∈ reachable_positions s g e ∧
strategy_order s (lnth p (Suc i), the (energy_level e0 p (Suc i)))
(lnth p i, the (energy_level e0 p i))"
proof
show "energy_level e0 p i ≠ None" using ‹⋀i. (energy_level e0 p i) = Some (snd (f i))› by simp
show "(lnth p i, the (energy_level e0 p i)) ∈ reachable_positions s g e ∧
strategy_order s (lnth p (Suc i), the (energy_level e0 p (Suc i)))
(lnth p i, the (energy_level e0 p i)) "
proof
show "(lnth p i, the (energy_level e0 p i)) ∈ reachable_positions s g e"
using ‹⋀i. (energy_level e0 p i) = Some (snd (f i))› F ‹⋀i. lnth p i = fst (f i)›
by simp
show "strategy_order s (lnth p (Suc i), the (energy_level e0 p (Suc i)))
(lnth p i, the (energy_level e0 p i))"
using ‹⋀i. strategy_order s (f (Suc i)) (f i)› ‹⋀i. lnth p i = fst (f i)› ‹⋀i. (energy_level e0 p i) = Some (snd (f i))›
by (metis option.sel split_pairs)
qed
qed
qed
qed
qed
hence "Q s p e0" using Q_def by simp
have "⋀s v Ps e'.
(¬ lfinite (LCons v Ps) ∧
valid_play (LCons v Ps) ∧
(∀i. energy_level e' (LCons v Ps) i ≠ None ∧
(lnth (LCons v Ps) i, the (energy_level e' (LCons v Ps) i)) ∈ reachable_positions s g e ∧
strategy_order s (lnth (LCons v Ps) (Suc i), the (energy_level e' (LCons v Ps) (Suc i)))
(lnth (LCons v Ps) i, the (energy_level e' (LCons v Ps) i)))) ∧
¬ lnull Ps ⟹
(¬ lfinite Ps ∧
valid_play Ps ∧
(∀i. energy_level (the (apply_w v (lhd Ps) e')) Ps i ≠ None ∧
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)) ∈ reachable_positions s g e ∧
strategy_order s (lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)))) ∧
(v ∈ attacker ⟶ s e' v = Some (lhd Ps)) ∧ (apply_w v (lhd Ps) e') ≠ None"
proof-
fix s v Ps e'
assume A: "(¬lfinite (LCons v Ps) ∧ valid_play (LCons v Ps) ∧ (∀i. energy_level e' (LCons v Ps) i ≠ None ∧
(lnth (LCons v Ps) i, the (energy_level e' (LCons v Ps) i))
∈ reachable_positions s g e ∧
strategy_order s (lnth (LCons v Ps) (Suc i), the (energy_level e' (LCons v Ps) (Suc i)))
(lnth (LCons v Ps) i, the (energy_level e' (LCons v Ps) i)))) ∧
¬ lnull Ps"
show "(¬lfinite Ps ∧ valid_play Ps ∧ (∀i. energy_level (the (apply_w v (lhd Ps) e')) Ps i ≠ None ∧
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i))
∈ reachable_positions s g e ∧
strategy_order s
(lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)))) ∧
(v ∈ attacker ⟶ s e' v = Some (lhd Ps))∧ (apply_w v (lhd Ps) e') ≠ None"
proof
show "¬lfinite Ps ∧valid_play Ps ∧ (∀i. energy_level (the (apply_w v (lhd Ps) e')) Ps i ≠ None ∧
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i))
∈ reachable_positions s g e ∧
strategy_order s
(lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)))"
proof
show "¬ lfinite Ps" using A by simp
show "valid_play Ps ∧
(∀i. energy_level (the (apply_w v (lhd Ps) e')) Ps i ≠ None ∧
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i))
∈ reachable_positions s g e ∧
strategy_order s
(lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)))"
proof
show "valid_play Ps" using A valid_play.simps
by (metis llist.distinct(1) llist.inject)
show "∀i. energy_level (the (apply_w v (lhd Ps) e')) Ps i ≠ None ∧
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i))
∈ reachable_positions s g e ∧
strategy_order s
(lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)) "
proof
fix i
show "energy_level (the (apply_w v (lhd Ps) e')) Ps i ≠ None ∧
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i))
∈ reachable_positions s g e ∧
strategy_order s
(lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i))"
proof
from A have "energy_level e' (LCons v Ps) (Suc i) ≠ None" by blast
from A have "valid_play (LCons v Ps) ∧ ¬ lnull Ps" by simp
have "apply_w v (lhd Ps) e' ≠ None" using energy_level.simps
by (metis A lhd_conv_lnth lnth_0 lnth_Suc_LCons option.sel)
from A have "enat i < (llength Ps)"
by (meson Suc_ile_eq ‹¬ lfinite Ps› enat_less_imp_le less_enatE lfinite_conv_llength_enat)
have EL: "energy_level (the (apply_w v (lhd Ps) e')) Ps i = energy_level e' (LCons v Ps) (Suc i)"
using energy_level_cons ‹valid_play (LCons v Ps) ∧ ¬ lnull Ps› ‹apply_w v (lhd Ps) e' ≠ None›
by (simp add: ‹enat i < llength Ps›)
thus "energy_level (the (apply_w v (lhd Ps) e')) Ps i ≠ None"
using ‹energy_level e' (LCons v Ps) (Suc i) ≠ None› by simp
show "(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)) ∈ reachable_positions s g e ∧
strategy_order s (lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i))"
proof
have "(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)) = (lnth (LCons v Ps) (Suc i), the (energy_level e' (LCons v Ps) (Suc i)))"
using EL by simp
thus "(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)) ∈ reachable_positions s g e"
using A by metis
have ‹enat (Suc i) < llength Ps›
using ‹¬ lfinite Ps› enat_iless linorder_less_linear llength_eq_enat_lfiniteD by blast
hence "(lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
= (lnth (LCons v Ps) (Suc (Suc i)), the (energy_level e' (LCons v Ps) (Suc (Suc i))))"
using energy_level_cons ‹valid_play (LCons v Ps) ∧ ¬ lnull Ps› ‹apply_w v (lhd Ps) e' ≠ None›
by (metis lnth_Suc_LCons)
thus "strategy_order s (lnth Ps (Suc i), the (energy_level (the (apply_w v (lhd Ps) e')) Ps (Suc i)))
(lnth Ps i, the (energy_level (the (apply_w v (lhd Ps) e')) Ps i)) " using A
by (metis EL lnth_Suc_LCons)
qed
qed
qed
qed
qed
show "(v ∈ attacker ⟶ s e' v = Some (lhd Ps))∧ (apply_w v (lhd Ps) e') ≠ None"
proof
show "v ∈ attacker ⟶ s e' v = Some (lhd Ps)"
proof
assume "v ∈ attacker"
from A have "strategy_order s (lnth (LCons v Ps) (Suc 0), the (energy_level e' (LCons v Ps) (Suc 0))) (lnth (LCons v Ps) 0, the (energy_level e' (LCons v Ps) 0))"
by blast
hence "strategy_order s ((lhd Ps), the (energy_level e' (LCons v Ps) (Suc 0))) (v, the (energy_level e' (LCons v Ps) 0))"
by (simp add: A lnth_0_conv_lhd)
hence "strategy_order s ((lhd Ps), the (energy_level e' (LCons v Ps) (Suc 0))) (v, e')" using energy_level.simps
by simp
hence "(if v ∈ attacker then Some (lhd Ps) = s e' v else weight v (lhd Ps) ≠ None)" using strategy_order_def
using split_beta split_pairs by auto
thus "s e' v = Some (lhd Ps)" using ‹v ∈ attacker› by auto
qed
from A have "energy_level (the (apply_w v (lhd Ps) e')) Ps 0 ≠ None" by auto
show "apply_w v (lhd Ps) e' ≠ None"
by (metis A energy_level.simps(1) energy_level.simps(2) eq_LConsD lnth_0 lnth_Suc_LCons not_lnull_conv option.sel)
qed
qed
qed
hence "(⋀s v Ps e'.
Q s (LCons v Ps) e' ∧ ¬ lnull Ps ⟹ (apply_w v (lhd Ps) e') ≠ None ∧
Q s Ps (the (apply_w v (lhd Ps) e')) ∧ (v ∈ attacker ⟶ s e' v = Some (lhd Ps)))" using Q_def by blast
hence "play_consistent_attacker s p e0"
using ‹Q s p e0› play_consistent_attacker_coinduct
by metis
have "valid_play (lappend (LCons g p') (ltl p)) ∧ play_consistent_attacker s (lappend (LCons g p') (ltl p)) e"
proof
have "weight (llast (LCons g p')) (lhd (ltl p)) ≠ None" using P'
by (metis ‹⋀i. lnth p i = fst (f i)› ‹¬ lfinite p› ‹f 0 = (g0, e0)› ‹valid_play p› fstI lfinite.simps lnth_0 ltl_simps(2) valid_play.cases)
show "valid_play (lappend (LCons g p') (ltl p))" using valid_play_append P'
by (metis (no_types, lifting) ‹¬ lfinite p› ‹valid_play p› ‹weight (llast (LCons g p')) (lhd (ltl p)) ≠ None› lfinite_LConsI lfinite_LNil llist.exhaust_sel ltl_simps(2) valid_play.simps)
have "energy_level e (LCons g p') (the_enat (llength p')) ≠ None"
by (metis P' not_Some_eq)
hence A: "lfinite p' ∧ llast (LCons g p') = lhd p ∧ play_consistent_attacker s p (the (energy_level e (LCons g p') (the_enat (llength p'))))
∧ play_consistent_attacker s (LCons g p') e ∧ valid_play (LCons g p') ∧ energy_level e (LCons g p') (the_enat (llength p')) ≠ None"
using P' ‹play_consistent_attacker s p e0› p_def ‹f 0 = (g0,e0)›
by (metis ‹⋀i. lnth p i = fst (f i)› ‹¬ lfinite p› fst_conv lhd_conv_lnth lnull_imp_lfinite option.sel)
show "play_consistent_attacker s (lappend (LCons g p') (ltl p)) e"
using A proof(induct "the_enat (llength p')" arbitrary: p' g e)
case 0
hence "(lappend (LCons g p') (ltl p)) = p"
by (metis ‹¬ lfinite p› gen_llength_code(1) lappend_code(1) lappend_code(2) lfinite_llength_enat lhd_LCons_ltl llast_singleton llength_LNil llength_code llength_eq_0 llist.collapse(1) the_enat.simps)
have "the (energy_level e (LCons g p') (the_enat (llength p'))) = e" using 0 energy_level.simps by auto
then show ?case using ‹(lappend (LCons g p') (ltl p)) = p› 0 by simp
next
case (Suc x)
hence "lhd p' = lhd (lappend (p') (ltl p))"
using the_enat_0 by auto
have "∃Ps. (lappend (LCons g p') (ltl p)) = LCons g Ps"
by simp
from this obtain Ps where "(lappend (LCons g p') (ltl p)) = LCons g Ps" by auto
hence "(lappend (p') (ltl p)) = Ps" by simp
have "g ∈ attacker ⟶ s e g = Some (lhd Ps)"
proof
assume "g ∈ attacker"
show "s e g = Some (lhd Ps)"
using Suc
by (metis Zero_not_Suc ‹g ∈ attacker› ‹lappend p' (ltl p) = Ps› ‹lhd p' = lhd (lappend p' (ltl p))› lhd_LCons llength_LNil llist.distinct(1) ltl_simps(2) play_consistent_attacker.cases the_enat_0)
qed
have "play_consistent_attacker s (lappend (LCons (lhd p') (ltl p')) (ltl p)) (the (apply_w g (lhd p') e))"
proof-
have "x = the_enat (llength (ltl p'))" using Suc
by (metis One_nat_def diff_Suc_1' epred_enat epred_llength lfinite_conv_llength_enat the_enat.simps)
have "lfinite (ltl p') ∧
llast (LCons (lhd p') (ltl p')) = lhd p ∧
play_consistent_attacker s p
(the (energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p')) (the_enat (llength (ltl p'))))) ∧
play_consistent_attacker s (LCons (lhd p') (ltl p')) (the (apply_w g (lhd p') e))
∧ valid_play (LCons (lhd p') (ltl p')) ∧ energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p')) (the_enat (llength (ltl p'))) ≠ None"
proof
show "lfinite (ltl p')" using Suc lfinite_ltl by simp
show "llast (LCons (lhd p') (ltl p')) = lhd p ∧
play_consistent_attacker s p
(the (energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p'))
(the_enat (llength (ltl p'))))) ∧
play_consistent_attacker s (LCons (lhd p') (ltl p')) (the (apply_w g (lhd p') e)) ∧
valid_play (LCons (lhd p') (ltl p')) ∧ energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p')) (the_enat (llength (ltl p'))) ≠ None"
proof
show "llast (LCons (lhd p') (ltl p')) = lhd p" using Suc
by (metis (no_types, lifting) ‹x = the_enat (llength (ltl p'))› llast_LCons2 llist.exhaust_sel ltl_simps(1) n_not_Suc_n)
show "play_consistent_attacker s p
(the (energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p'))
(the_enat (llength (ltl p'))))) ∧
play_consistent_attacker s (LCons (lhd p') (ltl p')) (the (apply_w g (lhd p') e)) ∧
valid_play (LCons (lhd p') (ltl p')) ∧ energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p')) (the_enat (llength (ltl p'))) ≠ None"
proof
have "energy_level e (LCons g p') (the_enat (llength p')) ≠ None" using Suc
by blast
hence "apply_w g (lhd p') e ≠ None"
by (smt (verit) Suc.hyps(2) Suc_leI ‹x = the_enat (llength (ltl p'))› energy_level.simps(1) energy_level_nth llist.distinct(1) llist.exhaust_sel lnth_0 lnth_Suc_LCons ltl_simps(1) n_not_Suc_n option.sel zero_less_Suc)
hence cons_assms: "valid_play (LCons g p') ∧ ¬ lnull p' ∧ apply_w g (lhd p') e ≠ None ∧ enat (the_enat (llength (ltl p'))) < llength p'"
using Suc
by (metis ‹x = the_enat (llength (ltl p'))› enat_ord_simps(2) lessI lfinite_conv_llength_enat lnull_def ltl_simps(1) n_not_Suc_n the_enat.simps)
have "(the (energy_level e (LCons g p') (the_enat (llength p')))) =
(the (energy_level e (LCons g p') (Suc (the_enat (llength (ltl p'))))))"
using Suc.hyps(2) ‹x = the_enat (llength (ltl p'))› by auto
also have "... = (the (energy_level (the (apply_w g (lhd p') e)) p' (the_enat (llength (ltl p')))))"
using energy_level_cons cons_assms by simp
finally have EL: "(the (energy_level e (LCons g p') (the_enat (llength p')))) =
(the (energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p')) (the_enat (llength (ltl p')))))"
by (simp add: cons_assms)
thus "play_consistent_attacker s p
(the (energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p'))
(the_enat (llength (ltl p')))))"
using Suc by argo
show "play_consistent_attacker s (LCons (lhd p') (ltl p')) (the (apply_w g (lhd p') e))∧
valid_play (LCons (lhd p') (ltl p')) ∧ energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p')) (the_enat (llength (ltl p'))) ≠ None"
proof
show " play_consistent_attacker s (LCons (lhd p') (ltl p')) (the (apply_w g (lhd p') e))"
using Suc
by (metis cons_assms lhd_LCons lhd_LCons_ltl llist.distinct(1) ltl_simps(2) play_consistent_attacker.simps)
show "valid_play (LCons (lhd p') (ltl p')) ∧ energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p')) (the_enat (llength (ltl p'))) ≠ None"
proof
show "valid_play (LCons (lhd p') (ltl p'))" using Suc
by (metis llist.distinct(1) llist.exhaust_sel llist.inject ltl_simps(1) valid_play.simps)
show "energy_level (the (apply_w g (lhd p') e)) (LCons (lhd p') (ltl p')) (the_enat (llength (ltl p'))) ≠ None"
using EL Suc
by (metis ‹x = the_enat (llength (ltl p'))› cons_assms energy_level_cons lhd_LCons_ltl)
qed
qed
qed
qed
qed
thus ?thesis using ‹x = the_enat (llength (ltl p'))› Suc
by blast
qed
hence "play_consistent_attacker s Ps (the (apply_w g (lhd p') e))"
using ‹(lappend (p') (ltl p)) = Ps›
by (metis Suc.hyps(2) diff_0_eq_0 diff_Suc_1 lhd_LCons_ltl llength_lnull n_not_Suc_n the_enat_0)
then show ?case using play_consistent_attacker.simps ‹g ∈ attacker ⟶ s e g = Some (lhd Ps)› ‹(lappend (LCons g p') (ltl p)) = LCons g Ps›
by (metis (no_types, lifting) Suc.prems ‹¬ lfinite p› ‹lappend p' (ltl p) = Ps› ‹lhd p' = lhd (lappend p' (ltl p))› energy_level.simps(1) lappend_code(1) lhd_LCons llast_singleton llength_LNil llist.distinct(1) lnull_lappend ltl_simps(2) option.sel the_enat_0)
qed
qed
hence "¬defender_wins_play e (lappend (LCons g p') (ltl p))" using assms unfolding attacker_winning_strategy.simps using P'
by simp
have "¬lfinite (lappend p' p)" using p_def by simp
hence "defender_wins_play e (lappend (LCons g p') (ltl p))" using defender_wins_play_def by auto
thus "False" using ‹¬defender_wins_play e (lappend (LCons g p') (ltl p))› by simp
qed
text‹We now show that an energy-positional attacker winning strategy w.r.t.\ some energy $e$ and position $g$
guarantees that $e$ is in the attacker winning budget of $g$.›
lemma winning_budget_implies_ind:
assumes "winning_budget e g"
shows "winning_budget_ind e g"
proof-
define wb where "wb ≡ λ(g,e). winning_budget_ind e g"
from assms have "∃s. attacker_winning_strategy s e g" using winning_budget.simps by auto
from this obtain s where S: "attacker_winning_strategy s e g" by auto
hence "wfp_on (strategy_order s) (reachable_positions s g e)"
using strategy_order_well_founded by simp
hence "inductive_on (strategy_order s) (reachable_positions s g e)"
by (simp add: wfp_on_iff_inductive_on)
hence "wb (g,e)"
proof(rule inductive_on_induct)
show "(g,e) ∈ reachable_positions s g e"
unfolding reachable_positions_def proof
have "lfinite LNil ∧
llast (LCons g LNil) = g ∧
valid_play (LCons g LNil) ∧ play_consistent_attacker s (LCons g LNil) e ∧
Some e = energy_level e (LCons g LNil) (the_enat (llength LNil))"
using valid_play.simps play_consistent_attacker.simps energy_level.simps
by (metis lfinite_code(1) llast_singleton llength_LNil neq_LNil_conv the_enat_0)
thus "∃g' e'.
(g, e) = (g', e') ∧
(∃p. lfinite p ∧
llast (LCons g p) = g' ∧
valid_play (LCons g p) ∧ play_consistent_attacker s (LCons g p) e ∧
Some e' = energy_level e (LCons g p) (the_enat (llength p)))"
by (metis lfinite_code(1) llast_singleton llength_LNil the_enat_0)
qed
show "⋀y. y ∈ reachable_positions s g e ⟹
(⋀x. x ∈ reachable_positions s g e ⟹ strategy_order s x y ⟹ wb x) ⟹ wb y"
proof-
fix y
assume "y ∈ reachable_positions s g e"
hence "∃e' g'. y = (g', e')" using reachable_positions_def by auto
from this obtain e' g' where "y = (g', e')" by auto
hence "(∃p. lfinite p ∧ llast (LCons g p) = g'
∧ valid_play (LCons g p)
∧ play_consistent_attacker s (LCons g p) e
∧ (Some e' = energy_level e (LCons g p) (the_enat (llength p))))"
using ‹y ∈ reachable_positions s g e› unfolding reachable_positions_def
by auto
from this obtain p where P: "(lfinite p ∧ llast (LCons g p) = g'
∧ valid_play (LCons g p)
∧ play_consistent_attacker s (LCons g p) e)
∧ (Some e' = energy_level e (LCons g p) (the_enat (llength p)))" by auto
show "(⋀x. x ∈ reachable_positions s g e ⟹ strategy_order s x y ⟹ wb x) ⟹ wb y"
proof-
assume ind: "(⋀x. x ∈ reachable_positions s g e ⟹ strategy_order s x y ⟹ wb x)"
have "winning_budget_ind e' g'"
proof(cases "g' ∈ attacker")
case True
then show ?thesis
proof(cases "deadend g'")
case True
hence "attacker_stuck (LCons g p)" using ‹g' ∈ attacker› P
by (meson S defender_wins_play_def attacker_winning_strategy.elims(2))
hence "defender_wins_play e (LCons g p)" using defender_wins_play_def by simp
have "¬defender_wins_play e (LCons g p)" using P S by simp
then show ?thesis using ‹defender_wins_play e (LCons g p)› by simp
next
case False
hence "(s e' g') ≠ None ∧ (weight g' (the (s e' g')))≠None" using S attacker_winning_strategy.simps
by (simp add: True attacker_strategy_def)
define x where "x = (the (s e' g'), the (apply_w g' (the (s e' g')) e'))"
define p' where "p' = (lappend p (LCons (the (s e' g')) LNil))"
hence "lfinite p'" using P by simp
have "llast (LCons g p') = the (s e' g')" using p'_def ‹lfinite p'›
by (simp add: llast_LCons)
have "the_enat (llength p') > 0" using P
by (metis LNil_eq_lappend_iff ‹lfinite p'› bot_nat_0.not_eq_extremum enat_0_iff(2) lfinite_conv_llength_enat llength_eq_0 llist.collapse(1) llist.distinct(1) p'_def the_enat.simps)
hence "∃i. Suc i = the_enat (llength p')"
using less_iff_Suc_add by auto
from this obtain i where "Suc i = the_enat (llength p')" by auto
hence "i = the_enat (llength p)" using p'_def P
by (metis Suc_leI ‹lfinite p'› length_append_singleton length_list_of_conv_the_enat less_Suc_eq_le less_irrefl_nat lfinite_LConsI lfinite_LNil list_of_LCons list_of_LNil list_of_lappend not_less_less_Suc_eq)
hence "Some e' = (energy_level e (LCons g p) i)" using P by simp
have A: "lfinite (LCons g p) ∧ i < the_enat (llength (LCons g p)) ∧ energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None"
proof
show "lfinite (LCons g p)" using P by simp
show "i < the_enat (llength (LCons g p)) ∧ energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None"
proof
show "i < the_enat (llength (LCons g p))" using ‹i = the_enat (llength p)› P
by (metis ‹lfinite (LCons g p)› length_Cons length_list_of_conv_the_enat lessI list_of_LCons)
show "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None" using P ‹i = the_enat (llength p)›
using S defender_wins_play_def by auto
qed
qed
hence "Some e' = (energy_level e (LCons g p') i)" using p'_def energy_level_append P ‹Some e' = (energy_level e (LCons g p) i)›
by (metis lappend_code(2))
hence "energy_level e (LCons g p') i ≠ None"
by (metis option.distinct(1))
have "enat (Suc i) = llength p'" using ‹Suc i = the_enat (llength p')›
by (metis ‹lfinite p'› lfinite_conv_llength_enat the_enat.simps)
also have "... < eSuc (llength p')"
by (metis calculation iless_Suc_eq order_refl)
also have "... = llength (LCons g p')" using ‹lfinite p'› by simp
finally have "enat (Suc i) < llength (LCons g p')".
have "(lnth (LCons g p) i) = g'" using ‹i = the_enat (llength p)› P
by (metis lfinite_conv_llength_enat llast_conv_lnth llength_LCons the_enat.simps)
hence "(lnth (LCons g p') i) = g'" using p'_def
by (metis P ‹i = the_enat (llength p)› enat_ord_simps(2) energy_level.elims lessI lfinite_llength_enat lnth_0 lnth_Suc_LCons lnth_lappend1 the_enat.simps)
have "energy_level e (LCons g p') (the_enat (llength p')) = energy_level e (LCons g p') (Suc i)"
using ‹Suc i = the_enat (llength p')› by simp
also have "... = apply_w (lnth (LCons g p') i) (lnth (LCons g p') (Suc i)) (the (energy_level e (LCons g p') i))"
using energy_level.simps ‹enat (Suc i) < llength (LCons g p')› ‹energy_level e (LCons g p') i ≠ None›
by (meson leD)
also have "... = apply_w (lnth (LCons g p') i) (lnth (LCons g p') (Suc i)) e'" using ‹Some e' = (energy_level e (LCons g p') i)›
by (metis option.sel)
also have "... = apply_w (lnth (LCons g p') i) (the (s e' g')) e'" using p'_def ‹enat (Suc i) = llength p'›
by (metis ‹eSuc (llength p') = llength (LCons g p')› ‹llast (LCons g p') = the (s e' g')› llast_conv_lnth)
also have "... = apply_w g' (the (s e' g')) e'" using ‹(lnth (LCons g p') i) = g'› by simp
finally have "energy_level e (LCons g p') (the_enat (llength p')) = apply_w g' (the (s e' g')) e'" .
have P': "lfinite p'∧
llast (LCons g p') = (the (s e' g')) ∧
valid_play (LCons g p') ∧ play_consistent_attacker s (LCons g p') e ∧
Some (the (apply_w g' (the (s e' g')) e')) = energy_level e (LCons g p') (the_enat (llength p'))"
proof
show "lfinite p'" using p'_def P by simp
show "llast (LCons g p') = the (s e' g') ∧
valid_play (LCons g p') ∧
play_consistent_attacker s (LCons g p') e ∧
Some (the (apply_w g' (the (s e' g')) e')) = energy_level e (LCons g p') (the_enat (llength p'))"
proof
show "llast (LCons g p') = the (s e' g')" using p'_def ‹lfinite p'›
by (simp add: llast_LCons)
show "valid_play (LCons g p') ∧
play_consistent_attacker s (LCons g p') e ∧
Some (the (apply_w g' (the (s e' g')) e')) = energy_level e (LCons g p') (the_enat (llength p'))"
proof
show "valid_play (LCons g p')" using p'_def P
using ‹s e' g' ≠ None ∧ weight g' (the (s e' g')) ≠ None› valid_play.intros(2) valid_play_append by auto
show "play_consistent_attacker s (LCons g p') e ∧
Some (the (apply_w g' (the (s e' g')) e')) = energy_level e (LCons g p') (the_enat (llength p'))"
proof
have "(LCons g p') = lappend (LCons g p) (LCons (the (s e' g')) LNil)" using p'_def
by simp
have "play_consistent_attacker s (lappend (LCons g p) (LCons (the (s e' g')) LNil)) e"
proof (rule play_consistent_attacker_append_one)
show "play_consistent_attacker s (LCons g p) e"
using P by auto
show "lfinite (LCons g p)" using P by auto
show "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None" using P
using A by auto
show "valid_play (lappend (LCons g p) (LCons (the (s e' g')) LNil))"
using ‹valid_play (LCons g p')› ‹(LCons g p') = lappend (LCons g p) (LCons (the (s e' g')) LNil)› by simp
show "llast (LCons g p) ∈ attacker ⟶
Some (the (s e' g')) =
s (the (energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1))) (llast (LCons g p))"
proof
assume "llast (LCons g p) ∈ attacker"
show "Some (the (s e' g')) =
s (the (energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1))) (llast (LCons g p))"
using ‹llast (LCons g p) ∈ attacker› P
by (metis One_nat_def ‹s e' g' ≠ None ∧ weight g' (the (s e' g')) ≠ None› diff_Suc_1' eSuc_enat lfinite_llength_enat llength_LCons option.collapse option.sel the_enat.simps)
qed
qed
thus "play_consistent_attacker s (LCons g p') e" using ‹(LCons g p') = lappend (LCons g p) (LCons (the (s e' g')) LNil)› by simp
show "Some (the (apply_w g' (the (s e' g')) e')) = energy_level e (LCons g p') (the_enat (llength p'))"
by (metis ‹eSuc (llength p') = llength (LCons g p')› ‹enat (Suc i) = llength p'› ‹energy_level e (LCons g p') (the_enat (llength p')) = apply_w g' (the (s e' g')) e'› ‹play_consistent_attacker s (LCons g p') e› ‹valid_play (LCons g p')› S defender_wins_play_def diff_Suc_1 eSuc_enat option.collapse attacker_winning_strategy.elims(2) the_enat.simps)
qed
qed
qed
qed
hence "x ∈ reachable_positions s g e" using reachable_positions_def x_def by auto
have "(apply_w g' (the (s e' g')) e') ≠ None" using P'
by (metis ‹energy_level e (LCons g p') (the_enat (llength p')) = apply_w g' (the (s e' g')) e'› option.distinct(1))
have "Some (the (apply_w g' (the (s e' g')) e')) = apply_w g' (the (s e' g')) e' ∧ (if g' ∈ attacker then Some (the (s e' g')) = s e' g' else weight g' (the (s e' g')) ≠ None)"
using ‹(s e' g') ≠ None ∧ (weight g' (the (s e' g')))≠None› ‹(apply_w g' (the (s e' g')) e') ≠ None› by simp
hence "strategy_order s x y" unfolding strategy_order_def using x_def ‹y = (g', e')›
by blast
hence "wb x" using ind ‹x ∈ reachable_positions s g e› by simp
hence "winning_budget_ind (the (apply_w g' (the (s e' g')) e')) (the (s e' g'))" using wb_def x_def by simp
then show ?thesis using ‹g' ∈ attacker› winning_budget_ind.simps
by (metis (mono_tags, lifting) ‹s e' g' ≠ None ∧ weight g' (the (s e' g')) ≠ None› ‹strategy_order s x y› ‹y = (g', e')› old.prod.case option.distinct(1) strategy_order_def x_def)
qed
next
case False
hence "g' ∉ attacker ∧
(∀g''. weight g' g'' ≠ None ⟶
apply_w g' g'' e' ≠ None ∧ winning_budget_ind (the (apply_w g' g'' e')) g'')"
proof
show "∀g''. weight g' g'' ≠ None ⟶
apply_w g' g'' e' ≠ None ∧ winning_budget_ind (the (apply_w g' g'' e')) g''"
proof
fix g''
show "weight g' g'' ≠ None ⟶
apply_w g' g'' e' ≠ None ∧ winning_budget_ind (the (apply_w g' g'' e')) g'' "
proof
assume "weight g' g'' ≠ None"
show "apply_w g' g'' e' ≠ None ∧ winning_budget_ind (the (apply_w g' g'' e')) g''"
proof
show "apply_w g' g'' e' ≠ None"
proof
assume "apply_w g' g'' e' = None"
define p' where "p' ≡ (LCons g (lappend p (LCons g'' LNil)))"
hence "lfinite p'" using P by simp
have "∃i. llength p = enat i" using P
by (simp add: lfinite_llength_enat)
from this obtain i where "llength p = enat i" by auto
hence "llength (lappend p (LCons g'' LNil)) = enat (Suc i)"
by (simp add: ‹llength p = enat i› eSuc_enat iadd_Suc_right)
hence "llength p' = eSuc (enat(Suc i))" using p'_def
by simp
hence "the_enat (llength p') = Suc (Suc i)"
by (simp add: eSuc_enat)
hence "the_enat (llength p') - 1 = Suc i"
by simp
hence "the_enat (llength p') - 1 = the_enat (llength (lappend p (LCons g'' LNil)))"
using ‹llength (lappend p (LCons g'' LNil)) = enat (Suc i)›
by simp
have "(lnth p' i) = g'" using p'_def ‹llength p = enat i› P
by (smt (verit) One_nat_def diff_Suc_1' enat_ord_simps(2) energy_level.elims lessI llast_conv_lnth llength_LCons lnth_0 lnth_LCons' lnth_lappend the_enat.simps)
have "(lnth p' (Suc i)) = g''" using p'_def ‹llength p = enat i›
by (metis ‹llength p' = eSuc (enat (Suc i))› lappend.disc(2) llast_LCons llast_conv_lnth llast_lappend_LCons llength_eq_enat_lfiniteD llist.disc(1) llist.disc(2))
have "p' = lappend (LCons g p) (LCons g'' LNil)" using p'_def by simp
hence "the (energy_level e p' i) = the (energy_level e (lappend (LCons g p) (LCons g'' LNil)) i)" by simp
also have "... = the (energy_level e (LCons g p) i)" using ‹llength p = enat i› energy_level_append P
by (metis diff_Suc_1 eSuc_enat lessI lfinite_LConsI llength_LCons option.distinct(1) the_enat.simps)
also have "... = e'" using P
by (metis ‹llength p = enat i› option.sel the_enat.simps)
finally have "the (energy_level e p' i) = e'" .
hence "apply_w (lnth p' i) (lnth p' (Suc i)) (the (energy_level e p' i)) = None" using ‹apply_w g' g'' e'=None› ‹(lnth p' i) = g'› ‹(lnth p' (Suc i)) = g''› by simp
have "energy_level e p' (the_enat (llength p') - 1) =
energy_level e p' (the_enat (llength (lappend p (LCons g'' LNil))))"
using ‹the_enat (llength p') - 1 = the_enat (llength (lappend p (LCons g'' LNil)))›
by simp
also have "... = energy_level e p' (Suc i)" using ‹llength (lappend p (LCons g'' LNil)) = enat (Suc i)› by simp
also have "... = (if energy_level e p' i = None ∨ llength p' ≤ enat (Suc i) then None
else apply_w (lnth p' i) (lnth p' (Suc i)) (the (energy_level e p' i)))" using energy_level.simps by simp
also have "... = None " using ‹apply_w (lnth p' i) (lnth p' (Suc i)) (the (energy_level e p' i)) = None›
by simp
finally have "energy_level e p' (the_enat (llength p') - 1) = None" .
hence "defender_wins_play e p'" unfolding defender_wins_play_def by simp
have "valid_play p'"
by (metis P ‹p' = lappend (LCons g p) (LCons g'' LNil)› ‹weight g' g'' ≠ None› energy_game.valid_play.intros(2) energy_game.valid_play_append lfinite_LConsI)
have "play_consistent_attacker s (lappend (LCons g p) (LCons g'' LNil)) e"
proof(rule play_consistent_attacker_append_one)
show "play_consistent_attacker s (LCons g p) e"
using P by simp
show "lfinite (LCons g p)" using P by simp
show "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None"
using P
by (meson S defender_wins_play_def attacker_winning_strategy.elims(2))
show "valid_play (lappend (LCons g p) (LCons g'' LNil))"
using ‹valid_play p'› ‹p' = lappend (LCons g p) (LCons g'' LNil)› by simp
show "llast (LCons g p) ∈ attacker ⟶
Some g'' =
s (the (energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1))) (llast (LCons g p))"
using False P by simp
qed
hence "play_consistent_attacker s p' e"
using ‹p' = lappend (LCons g p) (LCons g'' LNil)› by simp
hence "¬defender_wins_play e p'" using ‹valid_play p'› p'_def S by simp
thus "False" using ‹defender_wins_play e p'› by simp
qed
define x where "x = (g'', the (apply_w g' g'' e'))"
have "wb x"
proof(rule ind)
have "(∃p. lfinite p ∧
llast (LCons g p) = g'' ∧
valid_play (LCons g p) ∧ play_consistent_attacker s (LCons g p) e ∧
Some (the (apply_w g' g'' e')) = energy_level e (LCons g p) (the_enat (llength p)))"
proof
define p' where "p' = lappend p (LCons g'' LNil)"
show "lfinite p' ∧
llast (LCons g p') = g'' ∧
valid_play (LCons g p') ∧ play_consistent_attacker s (LCons g p') e ∧
Some (the (apply_w g' g'' e')) = energy_level e (LCons g p') (the_enat (llength p'))"
proof
show "lfinite p'" using P p'_def by simp
show "llast (LCons g p') = g'' ∧
valid_play (LCons g p') ∧
play_consistent_attacker s (LCons g p') e ∧
Some (the (apply_w g' g'' e')) = energy_level e (LCons g p') (the_enat (llength p'))"
proof
show "llast (LCons g p') = g''" using p'_def
by (metis ‹lfinite p'› lappend.disc_iff(2) lfinite_lappend llast_LCons llast_lappend_LCons llast_singleton llist.discI(2))
show "valid_play (LCons g p') ∧
play_consistent_attacker s (LCons g p') e ∧
Some (the (apply_w g' g'' e')) = energy_level e (LCons g p') (the_enat (llength p'))"
proof
show "valid_play (LCons g p')" using p'_def P
using ‹weight g' g'' ≠ None› lfinite_LCons valid_play.intros(2) valid_play_append by auto
show "play_consistent_attacker s (LCons g p') e ∧
Some (the (apply_w g' g'' e')) = energy_level e (LCons g p') (the_enat (llength p')) "
proof
have "play_consistent_attacker s (lappend (LCons g p) (LCons g'' LNil)) e"
proof(rule play_consistent_attacker_append_one)
show "play_consistent_attacker s (LCons g p) e"
using P by simp
show "lfinite (LCons g p)" using P by simp
show "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None"
using P
by (meson S defender_wins_play_def attacker_winning_strategy.elims(2))
show "valid_play (lappend (LCons g p) (LCons g'' LNil))"
using ‹valid_play (LCons g p')› p'_def by simp
show "llast (LCons g p) ∈ attacker ⟶
Some g'' =
s (the (energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1))) (llast (LCons g p))"
using False P by simp
qed
thus "play_consistent_attacker s (LCons g p') e" using p'_def
by (simp add: lappend_code(2))
have "∃i. Suc i = the_enat (llength p')" using p'_def ‹lfinite p'›
by (metis P length_append_singleton length_list_of_conv_the_enat lfinite_LConsI lfinite_LNil list_of_LCons list_of_LNil list_of_lappend)
from this obtain i where "Suc i = the_enat (llength p')" by auto
hence "i = the_enat (llength p)" using p'_def
by (smt (verit) One_nat_def ‹lfinite p'› add.commute add_Suc_shift add_right_cancel length_append length_list_of_conv_the_enat lfinite_LNil lfinite_lappend list.size(3) list.size(4) list_of_LCons list_of_LNil list_of_lappend plus_1_eq_Suc)
hence "Suc i = llength (LCons g p)"
using P eSuc_enat lfinite_llength_enat by fastforce
have "(LCons g p') = lappend (LCons g p) (LCons g'' LNil)" using p'_def by simp
have A: "lfinite (LCons g p) ∧ i < the_enat (llength (LCons g p)) ∧ energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None"
proof
show "lfinite (LCons g p)" using P by simp
show " i < the_enat (llength (LCons g p)) ∧
energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None "
proof
have "(llength p') = llength (LCons g p)" using p'_def
by (metis P ‹lfinite p'› length_Cons length_append_singleton length_list_of lfinite_LConsI lfinite_LNil list_of_LCons list_of_LNil list_of_lappend)
thus "i < the_enat (llength (LCons g p))" using ‹Suc i = the_enat (llength p')›
using lessI by force
show "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None" using P
by (meson S energy_game.defender_wins_play_def energy_game.play_consistent_attacker.intros(2) attacker_winning_strategy.simps)
qed
qed
hence "energy_level e (LCons g p') i ≠ None"
using energy_level_append
by (smt (verit) Nat.lessE Suc_leI ‹LCons g p' = lappend (LCons g p) (LCons g'' LNil)› diff_Suc_1 energy_level_nth)
have "enat (Suc i) < llength (LCons g p')"
using ‹Suc i = the_enat (llength p')›
by (metis Suc_ile_eq ‹lfinite p'› ldropn_Suc_LCons leI lfinite_conv_llength_enat lnull_ldropn nless_le the_enat.simps)
hence el_prems: "energy_level e (LCons g p') i ≠ None ∧ llength (LCons g p') > enat (Suc i)" using ‹energy_level e (LCons g p') i ≠ None› by simp
have "(lnth (LCons g p') i) = lnth (LCons g p) i"
unfolding ‹(LCons g p') = lappend (LCons g p) (LCons g'' LNil)› using ‹i = the_enat (llength p)› lnth_lappend1
by (metis A enat_ord_simps(2) length_list_of length_list_of_conv_the_enat)
have "lnth (LCons g p) i = llast (LCons g p)" using ‹Suc i = llength (LCons g p)›
by (metis enat_ord_simps(2) lappend_LNil2 ldropn_LNil ldropn_Suc_conv_ldropn ldropn_lappend lessI less_not_refl llast_ldropn llast_singleton)
hence "(lnth (LCons g p') i) = g'" using P
by (simp add: ‹lnth (LCons g p') i = lnth (LCons g p) i›)
have "(lnth (LCons g p') (Suc i)) = g''"
using p'_def ‹Suc i = the_enat (llength p')›
by (smt (verit) ‹enat (Suc i) < llength (LCons g p')› ‹lfinite p'› ‹llast (LCons g p') = g''› lappend_snocL1_conv_LCons2 ldropn_LNil ldropn_Suc_LCons ldropn_Suc_conv_ldropn ldropn_lappend2 lfinite_llength_enat llast_ldropn llast_singleton the_enat.simps wlog_linorder_le)
have "energy_level e (LCons g p) i = energy_level e (LCons g p') i"
using energy_level_append A ‹(LCons g p') = lappend (LCons g p) (LCons g'' LNil)›
by presburger
hence "Some e' = (energy_level e (LCons g p') i)"
using P ‹i = the_enat (llength p)›
by argo
have "energy_level e (LCons g p') (the_enat (llength p')) = energy_level e (LCons g p') (Suc i)" using ‹Suc i = the_enat (llength p')› by simp
also have "... = apply_w (lnth (LCons g p') i) (lnth (LCons g p') (Suc i)) (the (energy_level e (LCons g p') i))"
using energy_level.simps el_prems
by (meson leD)
also have "... = apply_w g' g'' (the (energy_level e (LCons g p') i))"
using ‹(lnth (LCons g p') i) = g'› ‹(lnth (LCons g p') (Suc i)) = g''› by simp
finally have "energy_level e (LCons g p') (the_enat (llength p')) = (apply_w g' g'' e')"
using ‹Some e' = (energy_level e (LCons g p') i)›
by (metis option.sel)
thus "Some (the (apply_w g' g'' e')) = energy_level e (LCons g p') (the_enat (llength p'))"
by (simp add: ‹apply_w g' g'' e' ≠ None›)
qed
qed
qed
qed
qed
thus "x ∈ reachable_positions s g e"
using x_def reachable_positions_def
by (simp add: mem_Collect_eq)
have "Some (the (apply_w g' g'' e')) = apply_w g' g'' e' ∧
(if g' ∈ attacker then Some g'' = s e' g' else weight g' g'' ≠ None)"
proof
show "Some (the (apply_w g' g'' e')) = apply_w g' g'' e'"
by (simp add: ‹apply_w g' g'' e' ≠ None›)
show "(if g' ∈ attacker then Some g'' = s e' g' else weight g' g'' ≠ None)"
using False
by (simp add: ‹weight g' g'' ≠ None›)
qed
thus "strategy_order s x y" using strategy_order_def x_def ‹y = (g', e')›
by simp
qed
thus "winning_budget_ind (the (apply_w g' g'' e')) g'' " using x_def wb_def
by force
qed
qed
qed
qed
thus ?thesis using winning_budget_ind.intros by blast
qed
thus "wb y" using ‹y = (g', e')› wb_def by simp
qed
qed
qed
thus ?thesis using wb_def by simp
qed
text ‹We now prepare the proof of ‹winning_budget_ind› characterising subsets of ‹winning_budget_nonpos› for all positions.
For this we introduce a construction to obtain a non-positional attacker winning strategy from a strategy at a next position.›
fun nonpos_strat_from_next:: "'position ⇒ 'position ⇒
('position list ⇒ 'position option) ⇒ ('position list ⇒ 'position option)"
where
"nonpos_strat_from_next g g' s [] = s []" |
"nonpos_strat_from_next g g' s (x#xs) = (if x=g then (if xs=[] then Some g'
else s xs) else s (x#xs))"
lemma play_nonpos_consistent_next:
assumes "play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons g (LCons g' xs)) []"
and "g ∈ attacker" and "xs ≠ LNil"
shows "play_consistent_attacker_nonpos s (LCons g' xs) []"
proof-
have X: "⋀l. l≠[] ⟹(((nonpos_strat_from_next g g' s) ([g] @ l)) = s l)" using nonpos_strat_from_next.simps by simp
have A1: "⋀s v l. play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons v LNil) ([g]@l) ⟹ (l = [] ∨ (last l) ∉ attacker ∨ ((last l)∈attacker ∧ the (s l) = v))"
proof-
fix s v l
assume "play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons v LNil) ([g] @ l)"
show "l = [] ∨ last l ∉ attacker ∨ last l ∈ attacker ∧ the (s l) = v "
proof(cases "l=[]")
case True
then show ?thesis by simp
next
case False
hence "l ≠ []" .
then show ?thesis proof(cases "last l ∉ attacker")
case True
then show ?thesis by simp
next
case False
hence "the ((nonpos_strat_from_next g g' s) ([g] @ l)) = v"
by (smt (verit) ‹play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons v LNil) ([g] @ l)› append_is_Nil_conv assms(2) eq_LConsD last.simps last_append lhd_LCons list.distinct(1) llist.disc(1) play_consistent_attacker_nonpos.simps)
hence "the (s l) = v" using X ‹l ≠ []› by auto
then show ?thesis using False by simp
qed
qed
qed
have A2: "⋀s v Ps l. play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons v Ps) ([g]@l) ∧ Ps≠LNil ⟹ play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) Ps ([g]@(l@[v])) ∧ (v∈attacker ⟶ lhd Ps = the (s (l@[v])))"
proof-
fix s v Ps l
assume play_cons: "play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons v Ps) ([g]@l) ∧ Ps≠LNil"
show "play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) Ps ([g]@(l@[v])) ∧ (v∈attacker ⟶ lhd Ps = the (s (l@[v])))"
proof
show "play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) Ps ([g]@(l@[v]))" using play_cons play_consistent_attacker_nonpos.simps
by (smt (verit) append_assoc lhd_LCons llist.distinct(1) ltl_simps(2))
show "v ∈ attacker ⟶ lhd Ps = the (s (l @ [v]))"
proof
assume "v ∈ attacker"
hence "lhd Ps = the ((nonpos_strat_from_next g g' s) ([g]@(l @ [v])))" using play_cons play_consistent_attacker_nonpos.simps
by (smt (verit) append_assoc lhd_LCons llist.distinct(1) ltl_simps(2))
thus "lhd Ps = the (s (l @ [v]))" using X by auto
qed
qed
qed
have "play_consistent_attacker_nonpos s xs [g']" proof (rule play_consistent_attacker_nonpos_coinduct)
show "play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) xs ([g]@[g'])" using assms(1)
by (metis A2 append_Cons append_Nil assms(3) llist.distinct(1) play_consistent_attacker_nonpos_cons_simp)
show "⋀s v l.
play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons v LNil) ([g] @ l) ⟹
l = [] ∨ last l ∉ attacker ∨ last l ∈ attacker ∧ the (s l) = v" using A1 by auto
show "⋀s v Ps l.
play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons v Ps) ([g] @ l) ∧ Ps ≠ LNil ⟹
play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) Ps ([g] @ l @ [v]) ∧ (v ∈ attacker ⟶ lhd Ps = the (s (l @ [v])))" using A2 by auto
qed
thus ?thesis
by (metis A2 append.left_neutral append_Cons assms(1) llist.distinct(1) lnull_def play_consistent_attacker_nonpos_cons_simp)
qed
text‹We now introduce a construction to obtain a non-positional attacker winning strategy from a strategy at a previous position.›
fun nonpos_strat_from_previous:: "'position ⇒ 'position ⇒
('position list ⇒ 'position option) ⇒ ('position list ⇒ 'position option)"
where
"nonpos_strat_from_previous g g' s [] = s []" |
"nonpos_strat_from_previous g g' s (x#xs) = (if x=g' then s (g#(g'#xs))
else s (x#xs))"
lemma play_nonpos_consistent_previous:
assumes "play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) p ([g']@l)"
and "g∈attacker ⟹ g'=the (s [g])"
shows "play_consistent_attacker_nonpos s p ([g,g']@l)"
proof(rule play_consistent_attacker_nonpos_coinduct)
show "play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) p (tl([g,g']@l)) ∧ length ([g,g']@l) > 1 ∧ hd ([g,g']@l) = g ∧ hd (tl ([g,g']@l)) = g'" using assms(1) by simp
have X: "⋀l. nonpos_strat_from_previous g g' s ([g']@l) = s ([g,g']@l)" using nonpos_strat_from_previous.simps by simp
have Y: "⋀l. hd l ≠ g' ⟹ nonpos_strat_from_previous g g' s l = s l" using nonpos_strat_from_previous.simps
by (metis list.sel(1) neq_Nil_conv)
show "⋀s v l.
play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) (LCons v LNil) (tl l) ∧ 1 < length l ∧ hd l = g ∧ hd (tl l) = g' ⟹
l = [] ∨ last l ∉ attacker ∨ last l ∈ attacker ∧ the (s l) = v"
proof-
fix s v l
assume A: "play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) (LCons v LNil) (tl l) ∧ 1 < length l ∧ hd l = g ∧ hd (tl l) = g'"
show "l = [] ∨ last l ∉ attacker ∨ last l ∈ attacker ∧ the (s l) = v"
proof(cases "last l ∈ attacker")
case True
hence "last (tl l) ∈ attacker"
by (metis A hd_Cons_tl last_tl less_Suc0 remdups_adj.simps(2) remdups_adj_singleton remdups_adj_singleton_iff zero_neq_one)
hence "the (nonpos_strat_from_previous g g' s (tl l)) = v" using play_consistent_attacker_nonpos.simps A
by (smt (verit) length_tl less_numeral_extra(3) list.size(3) llist.disc(1) llist.distinct(1) llist.inject zero_less_diff)
hence "the (s l) = v" using X A
by (smt (verit, del_insts) One_nat_def hd_Cons_tl length_Cons less_numeral_extra(4) list.inject list.size(3) not_one_less_zero nonpos_strat_from_previous.elims)
then show ?thesis by simp
next
case False
then show ?thesis by simp
qed
qed
show "⋀s v Ps l.
(play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) (LCons v Ps) (tl l) ∧
1 < length l ∧ hd l = g ∧ hd (tl l) = g') ∧
Ps ≠ LNil ⟹
(play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) Ps (tl (l @ [v])) ∧
1 < length (l @ [v]) ∧ hd (l @ [v]) = g ∧ hd (tl (l @ [v])) = g') ∧
(v ∈ attacker ⟶ lhd Ps = the (s (l @ [v])))"
proof-
fix s v Ps l
assume A: "(play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) (LCons v Ps) (tl l) ∧
1 < length l ∧ hd l = g ∧ hd (tl l) = g') ∧ Ps ≠ LNil"
show "(play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) Ps (tl (l @ [v])) ∧
1 < length (l @ [v]) ∧ hd (l @ [v]) = g ∧ hd (tl (l @ [v])) = g') ∧
(v ∈ attacker ⟶ lhd Ps = the (s (l @ [v])))"
proof
show "play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) Ps (tl (l @ [v])) ∧
1 < length (l @ [v]) ∧ hd (l @ [v]) = g ∧ hd (tl (l @ [v])) = g'"
proof
show "play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) Ps (tl (l @ [v]))" using A play_consistent_attacker_nonpos.simps
by (smt (verit) lhd_LCons list.size(3) llist.distinct(1) ltl_simps(2) not_one_less_zero tl_append2)
show "1 < length (l @ [v]) ∧ hd (l @ [v]) = g ∧ hd (tl (l @ [v])) = g'" using A
by (metis Suc_eq_plus1 add.comm_neutral add.commute append_Nil hd_append2 length_append_singleton less_numeral_extra(4) list.exhaust_sel list.size(3) tl_append2 trans_less_add2)
qed
show "v ∈ attacker ⟶ lhd Ps = the (s (l @ [v]))"
proof
assume "v ∈ attacker"
hence "lhd Ps = the ((nonpos_strat_from_previous g g' s) (tl (l @ [v])))" using A play_consistent_attacker_nonpos.simps
by (smt (verit) lhd_LCons list.size(3) llist.distinct(1) ltl_simps(2) not_one_less_zero tl_append2)
thus "lhd Ps = the (s (l @ [v]))" using X A
by (smt (verit, ccfv_SIG) One_nat_def Suc_lessD ‹play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) Ps (tl (l @ [v])) ∧ 1 < length (l @ [v]) ∧ hd (l @ [v]) = g ∧ hd (tl (l @ [v])) = g'› butlast.simps(2) butlast_snoc hd_Cons_tl length_greater_0_conv list.inject nonpos_strat_from_previous.elims)
qed
qed
qed
qed
text‹With these constructions we can show that the winning budgets defined by non-positional strategies are a fixed point of the inductive characterisation.
›
lemma nonpos_winning_budget_implies_inductive:
assumes "nonpos_winning_budget e g"
shows "g ∈ attacker ⟹ (∃g'. (weight g g' ≠ None) ∧ (apply_w g g' e)≠ None
∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))" and
"g ∉ attacker ⟹ (∀g'. (weight g g' ≠ None) ⟶ (apply_w g g' e)≠ None
∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))"
proof-
from assms obtain s where S: "nonpos_attacker_winning_strategy s e g" unfolding nonpos_winning_budget.simps by auto
show "g ∈ attacker ⟹ (∃g'. (weight g g' ≠ None) ∧ (apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))"
proof-
assume "g∈ attacker"
have finite: "lfinite (LCons g LNil)" by simp
have play_cons_g: "play_consistent_attacker_nonpos s (LCons g LNil) []"
by (simp add: play_consistent_attacker_nonpos.intros(2))
have valid_play_g: "valid_play (LCons g LNil)"
by (simp add: valid_play.intros(2))
hence "¬defender_wins_play e (LCons g LNil)" using nonpos_attacker_winning_strategy.simps S play_cons_g by auto
hence "¬ deadend g" using finite defender_wins_play_def
by (simp add: ‹g ∈ attacker›)
hence "s [g] ≠ None" using nonpos_attacker_winning_strategy.simps attacker_nonpos_strategy_def S
by (simp add: ‹g ∈ attacker›)
show "(∃g'. (weight g g' ≠ None) ∧ (apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))"
proof
show "weight g (the (s [g])) ≠ None ∧ apply_w g (the (s [g])) e ≠ None ∧ nonpos_winning_budget (the (apply_w g (the (s [g])) e)) (the (s [g]))"
proof
show "weight g (the (s [g])) ≠ None" using nonpos_attacker_winning_strategy.simps attacker_nonpos_strategy_def S ‹¬ deadend g›
using ‹g ∈ attacker› by (metis last_ConsL not_Cons_self2)
show "apply_w g (the (s [g])) e ≠ None ∧
nonpos_winning_budget (the (apply_w g (the (s [g])) e)) (the (s [g]))"
proof
show "apply_w g (the (s [g])) e ≠ None"
proof-
have finite: "lfinite (LCons g (LCons (the (s [g])) LNil))" by simp
have play_cons_g': "play_consistent_attacker_nonpos s (LCons g (LCons (the (s [g])) LNil)) []" using play_cons_g play_consistent_attacker_nonpos.intros
by (metis append_Nil lhd_LCons llist.disc(2))
have valid_play_g': "valid_play (LCons g (LCons (the (s [g])) LNil))" using valid_play.intros valid_play_g
using ‹weight g (the (s [g])) ≠ None› by auto
hence "¬defender_wins_play e (LCons g (LCons (the (s [g])) LNil))" using nonpos_attacker_winning_strategy.simps S play_cons_g' by auto
hence notNone: "energy_level e (LCons g (LCons (the (s [g])) LNil)) 1 ≠ None" using finite defender_wins_play_def
by (metis One_nat_def diff_Suc_1 length_Cons length_list_of_conv_the_enat lfinite_LConsI lfinite_LNil list.size(3) list_of_LCons list_of_LNil)
hence "energy_level e (LCons g (LCons (the (s [g])) LNil)) 1 = apply_w (lnth (LCons g (LCons (the (s [g])) LNil)) 0)(lnth (LCons g (LCons (the (s [g])) LNil)) 1) (the (energy_level e (LCons g (LCons (the (s [g])) LNil)) 0))"
using energy_level.simps by (metis One_nat_def)
hence "energy_level e (LCons g (LCons (the (s [g])) LNil)) 1 = apply_w g (the (s [g])) e" by simp
thus "apply_w g (the (s [g])) e ≠ None" using notNone by simp
qed
show "nonpos_winning_budget (the (apply_w g (the (s [g])) e)) (the (s [g]))"
unfolding nonpos_winning_budget.simps proof
show "nonpos_attacker_winning_strategy (nonpos_strat_from_previous g (the (s [g])) s) (the (apply_w g (the (s [g])) e)) (the (s [g]))"
unfolding nonpos_attacker_winning_strategy.simps proof
show "attacker_nonpos_strategy (nonpos_strat_from_previous g (the (s [g])) s)" using S nonpos_strat_from_previous.simps
by (smt (verit) nonpos_strat_from_previous.elims nonpos_attacker_winning_strategy.elims(2) attacker_nonpos_strategy_def last.simps list.distinct(1))
show "∀p. play_consistent_attacker_nonpos (nonpos_strat_from_previous g (the (s [g])) s) (LCons (the (s [g])) p) [] ∧
valid_play (LCons (the (s [g])) p) ⟶
¬ defender_wins_play (the (apply_w g (the (s [g])) e)) (LCons (the (s [g])) p) "
proof
fix p
show "play_consistent_attacker_nonpos (nonpos_strat_from_previous g (the (s [g])) s) (LCons (the (s [g])) p) [] ∧
valid_play (LCons (the (s [g])) p) ⟶
¬ defender_wins_play (the (apply_w g (the (s [g])) e)) (LCons (the (s [g])) p) "
proof
assume A: "play_consistent_attacker_nonpos (nonpos_strat_from_previous g (the (s [g])) s) (LCons (the (s [g])) p) [] ∧
valid_play (LCons (the (s [g])) p)"
hence play_cons: "play_consistent_attacker_nonpos s (LCons g (LCons (the (s [g])) p)) []"
proof(cases "p = LNil")
case True
then show ?thesis using nonpos_strat_from_previous.simps play_consistent_attacker_nonpos.simps
by (smt (verit) lhd_LCons llist.discI(2) self_append_conv2)
next
case False
hence "play_consistent_attacker_nonpos (nonpos_strat_from_previous g (the (s [g])) s) p [(the (s [g]))]" using A play_consistent_attacker_nonpos.cases
using eq_Nil_appendI lhd_LCons by fastforce
have "(the (s [g])) ∈ attacker ⟹ lhd p = the ((nonpos_strat_from_previous g (the (s [g])) s) [(the (s [g]))])" using A play_consistent_attacker_nonpos.cases
by (simp add: False play_consistent_attacker_nonpos_cons_simp)
hence "(the (s [g])) ∈ attacker ⟹ lhd p = the (s [g,(the (s [g]))])" using nonpos_strat_from_previous.simps by simp
then show ?thesis using play_nonpos_consistent_previous
by (smt (verit, del_insts) False ‹play_consistent_attacker_nonpos (nonpos_strat_from_previous g (the (s [g])) s) p [the (s [g])]› append_Cons lhd_LCons llist.collapse(1) play_consistent_attacker_nonpos.intros(5) play_consistent_attacker_nonpos.intros(6) play_consistent_attacker_nonpos_cons_simp self_append_conv2)
qed
from A have "valid_play (LCons g (LCons (the (s [g])) p))"
using ‹weight g (the (s [g])) ≠ None› valid_play.intros(3) by auto
hence not_won: "¬ defender_wins_play e (LCons g (LCons (the (s [g])) p))" using S play_cons by simp
hence "lfinite (LCons g (LCons (the (s [g])) p))" using defender_wins_play_def by simp
hence finite: "lfinite (LCons (the (s [g])) p)" by simp
from not_won have no_deadend: "¬(llast (LCons (the (s [g])) p) ∈ attacker ∧ deadend (llast (LCons (the (s [g])) p)))"
by (simp add: defender_wins_play_def)
have suc: "Suc (the_enat (llength (LCons (the (s [g])) p)) - 1) = (the_enat (llength (LCons g (LCons (the (s [g])) p))) - 1)" using finite
by (smt (verit, ccfv_SIG) Suc_length_conv diff_Suc_1 length_list_of_conv_the_enat lfinite_LCons list_of_LCons)
have " the_enat (llength (LCons (the (s [g])) p)) - 1 < the_enat (llength (LCons (the (s [g])) p))" using finite
by (metis (no_types, lifting) diff_less lfinite_llength_enat llength_eq_0 llist.disc(2) not_less_less_Suc_eq the_enat.simps zero_enat_def zero_less_Suc zero_less_one)
hence cons_e_l:"valid_play (LCons g (LCons (the (s [g])) p)) ∧ lfinite (LCons (the (s [g])) p) ∧ ¬ lnull (LCons (the (s [g])) p) ∧ apply_w g (lhd (LCons (the (s [g])) p)) e ≠ None ∧ the_enat (llength (LCons (the (s [g])) p)) - 1 < the_enat (llength (LCons (the (s [g])) p))"
using ‹valid_play (LCons g (LCons (the (s [g])) p))› finite ‹apply_w g (the (s [g])) e ≠ None› by simp
from not_won have "energy_level e (LCons g (LCons (the (s [g])) p)) (the_enat (llength (LCons g (LCons (the (s [g])) p))) - 1) ≠ None"
by (simp add: defender_wins_play_def)
hence "energy_level (the (apply_w g (the (s [g])) e)) (LCons (the (s [g])) p) (the_enat (llength (LCons (the (s [g])) p)) - 1) ≠ None"
using energy_level_cons cons_e_l suc
by (metis enat_ord_simps(2) eq_LConsD length_list_of length_list_of_conv_the_enat)
thus "¬ defender_wins_play (the (apply_w g (the (s [g])) e)) (LCons (the (s [g])) p) " using finite no_deadend defender_wins_play_def by simp
qed
qed
qed
qed
qed
qed
qed
qed
show "g ∉ attacker ⟹ (∀g'. (weight g g' ≠ None) ⟶ (apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))"
proof-
assume "g∉attacker"
show "(∀g'. (weight g g' ≠ None) ⟶ (apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))"
proof
fix g'
show "(weight g g' ≠ None) ⟶ (apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g')"
proof
assume "(weight g g' ≠ None)"
show "(apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g')"
proof
have "valid_play (LCons g (LCons g' LNil))" using ‹(weight g g' ≠ None)›
by (simp add: valid_play.intros(2) valid_play.intros(3))
have "play_consistent_attacker_nonpos s (LCons g' LNil) [g]" using play_consistent_attacker_nonpos.intros(3)
by (simp add: ‹g ∉ attacker›)
hence "play_consistent_attacker_nonpos s (LCons g (LCons g' LNil)) []" using ‹g∉attacker› play_consistent_attacker_nonpos.intros(5) by simp
hence "¬defender_wins_play e (LCons g (LCons g' LNil))" using ‹valid_play (LCons g (LCons g' LNil))› S by simp
hence "energy_level e (LCons g (LCons g' LNil)) (the_enat (llength (LCons g (LCons g' LNil)))-1) ≠ None" using defender_wins_play_def by simp
hence "energy_level e (LCons g (LCons g' LNil)) 1 ≠ None"
by (metis One_nat_def diff_Suc_1 length_Cons length_list_of_conv_the_enat lfinite_LConsI lfinite_LNil list.size(3) list_of_LCons list_of_LNil)
thus "apply_w g g' e ≠ None" using energy_level.simps
by (metis One_nat_def lnth_0 lnth_Suc_LCons option.sel)
show "(nonpos_winning_budget (the (apply_w g g' e)) g')"
unfolding nonpos_winning_budget.simps proof
show "nonpos_attacker_winning_strategy (nonpos_strat_from_previous g g' s) (the (apply_w g g' e)) g'"
unfolding nonpos_attacker_winning_strategy.simps proof
show "attacker_nonpos_strategy (nonpos_strat_from_previous g g' s)" using S
by (smt (verit, del_insts) nonpos_strat_from_previous.elims nonpos_attacker_winning_strategy.elims(2) attacker_nonpos_strategy_def last_ConsR list.distinct(1))
show "∀p. play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) (LCons g' p) [] ∧ valid_play (LCons g' p) ⟶
¬ defender_wins_play (the (apply_w g g' e)) (LCons g' p)"
proof
fix p
show "play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) (LCons g' p) [] ∧ valid_play (LCons g' p) ⟶
¬ defender_wins_play (the (apply_w g g' e)) (LCons g' p) "
proof
assume A: "play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) (LCons g' p) [] ∧ valid_play (LCons g' p)"
hence "valid_play (LCons g (LCons g' p))"
using ‹weight g g' ≠ None› valid_play.intros(3) by auto
from A have "play_consistent_attacker_nonpos (nonpos_strat_from_previous g g' s) p [g']"
using play_consistent_attacker_nonpos.intros(1) play_consistent_attacker_nonpos_cons_simp by auto
hence "play_consistent_attacker_nonpos s p [g,g']" using play_nonpos_consistent_previous ‹g∉attacker›
by fastforce
hence "play_consistent_attacker_nonpos s (LCons g (LCons g' p)) []"
by (smt (verit) A Cons_eq_appendI ‹play_consistent_attacker_nonpos s (LCons g (LCons g' LNil)) []› eq_Nil_appendI lhd_LCons llist.discI(2) llist.distinct(1) ltl_simps(2) play_consistent_attacker_nonpos.simps nonpos_strat_from_previous.simps(2))
hence not_won: "¬defender_wins_play e (LCons g (LCons g' p))" using S ‹valid_play (LCons g (LCons g' p))› by simp
hence finite: "lfinite (LCons g' p)"
by (simp add: defender_wins_play_def)
from not_won have no_deadend: "¬(llast (LCons g' p) ∈ attacker ∧ deadend (llast (LCons g' p)))" using defender_wins_play_def by simp
have suc: "Suc ((the_enat (llength (LCons g' p)) - 1)) = (the_enat (llength (LCons g (LCons g' p))) - 1)"
using finite
by (smt (verit, ccfv_SIG) Suc_length_conv diff_Suc_1 length_list_of_conv_the_enat lfinite_LCons list_of_LCons)
from not_won have "energy_level e (LCons g (LCons g' p)) (the_enat (llength (LCons g (LCons g' p))) - 1) ≠ None" using defender_wins_play_def by simp
hence "energy_level (the (apply_w g g' e)) (LCons g' p) (the_enat (llength (LCons g' p)) - 1) ≠ None"
using suc energy_level_cons
by (smt (verit, best) One_nat_def Suc_diff_Suc Suc_lessD ‹apply_w g g' e ≠ None› ‹valid_play (LCons g (LCons g' p))› diff_zero enat_ord_simps(2) energy_level.elims lessI lfinite_conv_llength_enat lhd_LCons llist.discI(2) llist.distinct(1) local.finite option.collapse the_enat.simps zero_less_Suc zero_less_diff)
thus " ¬ defender_wins_play (the (apply_w g g' e)) (LCons g' p)" using defender_wins_play_def finite no_deadend by simp
qed
qed
qed
qed
qed
qed
qed
qed
qed
lemma inductive_implies_nonpos_winning_budget:
shows "g ∈ attacker ⟹ (∃g'. (weight g g' ≠ None) ∧ (apply_w g g' e)≠ None
∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))
⟹ nonpos_winning_budget e g"
and "g ∉ attacker ⟹ (∀g'. (weight g g' ≠ None)
⟶ (apply_w g g' e)≠ None
∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))
⟹ nonpos_winning_budget e g"
proof-
assume "g ∈ attacker"
assume "(∃g'. (weight g g' ≠ None) ∧ (apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))"
from this obtain g' where A1: "(weight g g' ≠ None) ∧ (apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g')" by auto
hence "∃s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g'" using nonpos_winning_budget.simps by auto
from this obtain s where s_winning: "nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g'" by auto
have "nonpos_attacker_winning_strategy (nonpos_strat_from_next g g' s) e g" unfolding nonpos_attacker_winning_strategy.simps
proof
show "attacker_nonpos_strategy (nonpos_strat_from_next g g' s)"
unfolding attacker_nonpos_strategy_def proof
fix list
show "list ≠ [] ⟶
last list ∈ attacker ∧ ¬ deadend (last list) ⟶
nonpos_strat_from_next g g' s list ≠ None ∧ weight (last list) (the (nonpos_strat_from_next g g' s list)) ≠ None"
proof
assume "list ≠ []"
show "last list ∈ attacker ∧ ¬ deadend (last list) ⟶
nonpos_strat_from_next g g' s list ≠ None ∧ weight (last list) (the (nonpos_strat_from_next g g' s list)) ≠ None"
proof
assume "last list ∈ attacker ∧ ¬ deadend (last list)"
show "nonpos_strat_from_next g g' s list ≠ None ∧ weight (last list) (the (nonpos_strat_from_next g g' s list)) ≠ None "
proof
from s_winning have "attacker_nonpos_strategy s" by auto
thus "nonpos_strat_from_next g g' s list ≠ None" using nonpos_strat_from_next.simps(2) ‹list ≠ []› ‹last list ∈ attacker ∧ ¬ deadend (last list)›
by (smt (verit) nonpos_strat_from_next.elims attacker_nonpos_strategy_def last_ConsR option.discI)
show "weight (last list) (the (nonpos_strat_from_next g g' s list)) ≠ None " using nonpos_strat_from_next.simps(2) ‹list ≠ []› ‹last list ∈ attacker ∧ ¬ deadend (last list)›
by (smt (verit) A1 ‹attacker_nonpos_strategy s› nonpos_strat_from_next.elims attacker_nonpos_strategy_def last_ConsL last_ConsR option.sel)
qed
qed
qed
qed
show "∀p. play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons g p) [] ∧ valid_play (LCons g p) ⟶
¬ defender_wins_play e (LCons g p) "
proof
fix p
show "play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons g p) [] ∧ valid_play (LCons g p) ⟶
¬ defender_wins_play e (LCons g p)"
proof
assume A: "play_consistent_attacker_nonpos (nonpos_strat_from_next g g' s) (LCons g p)[] ∧ valid_play (LCons g p)"
hence "play_consistent_attacker_nonpos s p []"
proof(cases "p=LNil")
case True
then show ?thesis
by (simp add: play_consistent_attacker_nonpos.intros(1))
next
case False
hence "∃v p'. p=LCons v p'"
by (meson llist.exhaust)
from this obtain v p' where "p= LCons v p'" by auto
then show ?thesis
proof(cases "p'=LNil")
case True
then show ?thesis
by (simp add: ‹p = LCons v p'› play_consistent_attacker_nonpos.intros(2))
next
case False
from ‹p= LCons v p'› have "v=g'" using A nonpos_strat_from_next.simps play_nonpos_consistent_previous ‹g ∈ attacker›
by (simp add: play_consistent_attacker_nonpos_cons_simp)
then show ?thesis using ‹p= LCons v p'› A nonpos_strat_from_next.simps play_nonpos_consistent_next
using False ‹g ∈ attacker› by blast
qed
qed
have "valid_play p" using A valid_play.simps
by (metis eq_LConsD)
hence notNil: "p≠LNil ⟹ ¬ defender_wins_play (the (apply_w g g' e)) p" using s_winning ‹play_consistent_attacker_nonpos s p []› nonpos_attacker_winning_strategy.elims
by (metis A ‹g ∈ attacker› lhd_LCons not_lnull_conv option.sel play_consistent_attacker_nonpos_cons_simp nonpos_strat_from_next.simps(2))
show " ¬ defender_wins_play e (LCons g p)"
proof(cases "p=LNil")
case True
hence "lfinite (LCons g p)" by simp
have "llast (LCons g p) = g" using True by simp
hence not_deadend: "¬ deadend (llast (LCons g p))" using A1 by auto
have "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None" using True
by (simp add: gen_llength_code(1) gen_llength_code(2) llength_code)
then show ?thesis using defender_wins_play_def not_deadend ‹lfinite (LCons g p)› by simp
next
case False
hence "¬ defender_wins_play (the (apply_w g g' e)) p" using notNil by simp
hence not: "lfinite p ∧ energy_level (the (apply_w g g' e)) p (the_enat (llength p) - 1) ≠ None ∧ ¬(llast p ∈ attacker ∧ deadend (llast p))" using defender_wins_play_def
by simp
hence "lfinite (LCons g p)" by simp
from False have "llast (LCons g p) = llast p"
by (meson llast_LCons llist.collapse(1))
hence "¬(llast (LCons g p) ∈ attacker ∧ deadend (llast (LCons g p)))" using not by simp
from ‹lfinite (LCons g p)› have "the_enat (llength (LCons g p)) = Suc (the_enat (llength p))"
by (metis eSuc_enat lfinite_LCons lfinite_conv_llength_enat llength_LCons the_enat.simps)
hence E:"(the_enat (llength (LCons g p)) - 1) = Suc (the_enat (llength p) - 1)" using ‹lfinite (LCons g p)› False
by (metis diff_Suc_1 diff_self_eq_0 gr0_implies_Suc i0_less less_enatE less_imp_diff_less lfinite_llength_enat llength_eq_0 llist.collapse(1) not the_enat.simps)
from False have "lhd p = g'" using A nonpos_strat_from_next.simps play_nonpos_consistent_previous ‹g∈attacker›
by (simp add: play_consistent_attacker_nonpos_cons_simp)
hence "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) = energy_level (the (apply_w g g' e)) p (the_enat (llength p) - 1)"
using energy_level_cons A not False A1 E
by (metis ‹the_enat (llength (LCons g p)) = Suc (the_enat (llength p))› diff_Suc_1 enat_ord_simps(2) lessI lfinite_conv_llength_enat play_consistent_attacker_nonpos_cons_simp the_enat.simps)
hence "energy_level e (LCons g p) (the_enat (llength (LCons g p)) - 1) ≠ None" using not by auto
then show ?thesis using defender_wins_play_def ‹lfinite (LCons g p)› ‹¬(llast (LCons g p) ∈ attacker ∧ deadend (llast (LCons g p)))› by auto
qed
qed
qed
qed
thus "nonpos_winning_budget e g" using nonpos_winning_budget.simps by auto
next
assume "g ∉ attacker"
assume all: "(∀g'. (weight g g' ≠ None) ⟶ (apply_w g g' e)≠ None ∧ (nonpos_winning_budget (the (apply_w g g' e)) g'))"
have valid: "attacker_nonpos_strategy (λlist. (case list of
[] ⇒ None |
[x] ⇒ (if x ∈ attacker ∧ ¬deadend x then Some (SOME y. weight x y ≠ None) else None) |
(x#(g'#xs)) ⇒ (if (x=g ∧ weight x g' ≠ None) then ((SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g' ) (g'#xs))
else (if (last (x#(g'#xs))) ∈ attacker ∧ ¬deadend (last (x#(g'#xs))) then Some (SOME y. weight (last (x#(g'#xs))) y ≠ None) else None))))"
unfolding attacker_nonpos_strategy_def proof
fix list
show "list ≠ [] ⟶
last list ∈ attacker ∧ ¬ deadend (last list) ⟶
(case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) ≠
None ∧
weight (last list)
(the (case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None)) ≠
None"
proof
assume "list ≠ []"
show "last list ∈ attacker ∧ ¬ deadend (last list) ⟶
(case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) ≠
None ∧
weight (last list)
(the (case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None)) ≠
None"
proof
assume "last list ∈ attacker ∧ ¬ deadend (last list)"
show "(case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) ≠
None ∧
weight (last list)
(the (case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None)) ≠
None"
proof
show "(case list of [] ⇒ None |
[x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) ≠ None"
proof(cases "length list = 1")
case True
then show ?thesis
by (smt (verit) One_nat_def ‹last list ∈ attacker ∧ ¬ deadend (last list)› append_butlast_last_id append_eq_Cons_conv butlast_snoc length_0_conv length_Suc_conv_rev list.simps(4) list.simps(5) option.discI)
next
case False
hence "∃x y xs. list = x # (y # xs)"
by (metis One_nat_def ‹list ≠ []› length_Cons list.exhaust list.size(3))
from this obtain x y xs where "list = x # (y # xs)" by auto
then show ?thesis proof(cases "(x=g ∧ weight x y ≠ None)")
case True
hence A: "(case list of [] ⇒ None |
[x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) = (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y) (y#xs)"
using ‹list = x # y # xs› list.simps(5) by fastforce
from all True have "∃s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y" by auto
hence "nonpos_attacker_winning_strategy (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y) (the (apply_w g y e)) y"
using some_eq_ex by metis
hence "attacker_nonpos_strategy (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y)"
by (meson nonpos_attacker_winning_strategy.simps)
hence "(SOME s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y) (y#xs) ≠ None"
using ‹last list ∈ attacker ∧ ¬ deadend (last list)› ‹list = x # (y # xs)›
by (simp add: list.distinct(1) attacker_nonpos_strategy_def)
then show ?thesis using A by simp
next
case False
hence "(case list of [] ⇒ None |
[x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) =
Some (SOME z. weight (last (x # y # xs)) z ≠ None)"
using ‹last list ∈ attacker ∧ ¬ deadend (last list)› ‹list = x # y # xs› by auto
then show ?thesis by simp
qed
qed
show "weight (last list)
(the (case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None)) ≠ None"
proof(cases "length list =1")
case True
hence "the (case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) = (SOME y. weight (last list) y ≠ None)"
using ‹last list ∈ attacker ∧ ¬ deadend (last list)›
by (smt (verit) Eps_cong One_nat_def ‹(case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None | x # g' # xs ⇒ if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g' # xs) else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs)) then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) ≠ None› last_snoc length_0_conv length_Suc_conv_rev list.case_eq_if list.sel(1) list.sel(3) option.sel self_append_conv2)
then show ?thesis
by (smt (verit, del_insts) ‹last list ∈ attacker ∧ ¬ deadend (last list)› some_eq_ex)
next
case False
hence "∃x y xs. list = x # (y # xs)"
by (metis One_nat_def ‹list ≠ []› length_Cons list.exhaust list.size(3))
from this obtain x y xs where "list = x # (y # xs)" by auto
then show ?thesis proof(cases "(x=g ∧ weight x y ≠ None)")
case True
hence "(case list of [] ⇒ None |
[x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) = (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y) (y#xs)"
using ‹list = x # y # xs› list.simps(5) by fastforce
from all True have "∃s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y" by auto
hence "nonpos_attacker_winning_strategy (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y) (the (apply_w g y e)) y"
using some_eq_ex by metis
then show ?thesis
by (smt (verit) ‹(case list of [] ⇒ None | [x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None | x # g' # xs ⇒ if x = g ∧ weight x g' ≠ None then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g' # xs) else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs)) then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) = (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g y e)) y) (y # xs)› ‹last list ∈ attacker ∧ ¬ deadend (last list)› ‹list = x # y # xs› attacker_nonpos_strategy_def nonpos_attacker_winning_strategy.elims(1) last_ConsR list.distinct(1))
next
case False
hence "(case list of [] ⇒ None |
[x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None) =
Some (SOME z. weight (last (x # y # xs)) z ≠ None)"
using ‹last list ∈ attacker ∧ ¬ deadend (last list)› ‹list = x # y # xs› by auto
then show ?thesis
by (smt (verit, del_insts) ‹last list ∈ attacker ∧ ¬ deadend (last list)› ‹list = x # y # xs› option.sel verit_sko_ex_indirect)
qed
qed
qed
qed
qed
qed
have winning: "(∀p. (play_consistent_attacker_nonpos (λlist. (case list of [] ⇒ None |
[x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None)) (LCons g p) []
∧ valid_play (LCons g p)) ⟶ ¬ defender_wins_play e (LCons g p))"
proof
fix p
show "(play_consistent_attacker_nonpos (λlist. (case list of [] ⇒ None |
[x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None)) (LCons g p) []
∧ valid_play (LCons g p)) ⟶ ¬ defender_wins_play e (LCons g p)"
proof
assume A: "(play_consistent_attacker_nonpos (λlist. (case list of [] ⇒ None |
[x] ⇒ if x ∈ attacker ∧ ¬ deadend x then Some (SOME y. weight x y ≠ None) else None
| x # g' # xs ⇒
if (x=g ∧ weight x g' ≠ None) then (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g') (g'#xs)
else if last (x # g' # xs) ∈ attacker ∧ ¬ deadend (last (x # g' # xs))
then Some (SOME y. weight (last (x # g' # xs)) y ≠ None) else None)) (LCons g p) []
∧ valid_play (LCons g p))"
show "¬ defender_wins_play e (LCons g p)"
proof(cases "p = LNil")
case True
hence "lfinite (LCons g p)"
by simp
from True have "llength (LCons g p) = enat 1"
by (simp add: gen_llength_code(1) gen_llength_code(2) llength_code)
hence "the_enat (llength (LCons g p))-1 = 0" by simp
hence "energy_level e (LCons g p) (the_enat (llength (LCons g p))-1) = Some e" using energy_level.simps
by simp
thus ?thesis using ‹g ∉ attacker› ‹lfinite (LCons g p)› defender_wins_play_def
by (simp add: True)
next
case False
hence "weight g (lhd p) ≠ None" using A
using llist.distinct(1) valid_play.cases by auto
hence "∃s. (nonpos_attacker_winning_strategy s (the (apply_w g (lhd p) e)) (lhd p)) ∧ play_consistent_attacker_nonpos s p []"
proof-
have "∃s. (nonpos_attacker_winning_strategy s (the (apply_w g (lhd p) e)) (lhd p))" using ‹weight g (lhd p) ≠ None› all by simp
hence a_win: "nonpos_attacker_winning_strategy (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g (lhd p) e)) (lhd p)) (the (apply_w g (lhd p) e)) (lhd p)"
by (smt (verit, del_insts) list.simps(9) nat.case_distrib nat.disc_eq_case(1) neq_Nil_conv take_Suc take_eq_Nil2 tfl_some verit_sko_forall')
define strat where Strat: "strat ≡ (SOME s. nonpos_attacker_winning_strategy s (the (apply_w g (lhd p) e)) (lhd p))"
define strategy where Strategy: "strategy ≡ (λlist. (case list of
[] ⇒ None |
[x] ⇒ (if x ∈ attacker ∧ ¬deadend x then Some (SOME y. weight x y ≠ None) else None) |
(x#(g'#xs)) ⇒ (if (x=g ∧ weight x g' ≠ None) then ((SOME s. nonpos_attacker_winning_strategy s (the (apply_w g g' e)) g' ) (g'#xs))
else (if (last (x#(g'#xs))) ∈ attacker ∧ ¬deadend (last (x#(g'#xs))) then Some (SOME y. weight (last (x#(g'#xs))) y ≠ None) else None))))"
hence "play_consistent_attacker_nonpos strategy (LCons g p) []" using A by simp
hence strategy_cons: "play_consistent_attacker_nonpos strategy (ltl p) [g, lhd p]" using play_consistent_attacker_nonpos.simps
by (smt (verit) False butlast.simps(2) last_ConsL last_ConsR lhd_LCons list.distinct(1) ltl_simps(2) play_consistent_attacker_nonpos_cons_simp snoc_eq_iff_butlast)
have tail: "⋀p'. strategy (g#((lhd p)#p')) = strat ((lhd p)#p')" unfolding Strategy Strat
by (simp add: ‹weight g (lhd p) ≠ None›)
define Q where Q: "⋀s P l. Q s P l ≡ play_consistent_attacker_nonpos strategy P (g#l)
∧ l ≠ [] ∧ (∀p'. strategy (g#((hd l)#p')) = s ((hd l)#p'))"
have "play_consistent_attacker_nonpos strat (ltl p) [lhd p]"
proof(rule play_consistent_attacker_nonpos_coinduct)
show "Q strat (ltl p) [lhd p]"
unfolding Q using tail strategy_cons False play_consistent_attacker_nonpos_cons_simp by auto
show "⋀s v l. Q s (LCons v LNil) l ⟹ l = [] ∨ last l ∉ attacker ∨ last l ∈ attacker ∧ the (s l) = v"
proof-
fix s v l
assume "Q s (LCons v LNil) l"
have "l≠[] ∧ last l ∈ attacker ⟹ the (s l) = v"
proof-
assume "l≠[] ∧ last l ∈ attacker"
hence "(∀p'. strategy (g#((hd l)#p')) = s ((hd l)#p'))" using ‹Q s (LCons v LNil) l› Q by simp
hence "s l = strategy (g#l)"
by (metis ‹l ≠ [] ∧ last l ∈ attacker› list.exhaust list.sel(1))
from ‹l≠[] ∧ last l ∈ attacker› have "last (g#l) ∈ attacker" by simp
from ‹Q s (LCons v LNil) l› have "the (strategy (g#l)) = v" unfolding Q using play_consistent_attacker_nonpos.simps ‹last (g#l) ∈ attacker›
using eq_LConsD list.discI llist.disc(1) by blast
thus "the (s l) = v" using ‹s l = strategy (g#l)› by simp
qed
thus "l = [] ∨ last l ∉ attacker ∨ last l ∈ attacker ∧ the (s l) = v" by auto
qed
show "⋀s v Ps l. Q s (LCons v Ps) l ∧ Ps ≠ LNil ⟹ Q s Ps (l @ [v]) ∧ (v ∈ attacker ⟶ lhd Ps = the (s (l @ [v])))"
proof-
fix s v Ps l
assume "Q s (LCons v Ps) l ∧ Ps ≠ LNil"
hence A: "play_consistent_attacker_nonpos strategy (LCons v Ps) (g#l)
∧ l≠ [] ∧ (∀p'. strategy (g#((hd l)#p')) = s ((hd l)#p'))" unfolding Q by simp
show "Q s Ps (l @ [v]) ∧ (v ∈ attacker ⟶ lhd Ps = the (s (l @ [v])))"
proof
show "Q s Ps (l @ [v])"
unfolding Q proof
show "play_consistent_attacker_nonpos strategy Ps (g # l @ [v])"
using A play_consistent_attacker_nonpos.simps
by (smt (verit) Cons_eq_appendI lhd_LCons llist.distinct(1) ltl_simps(2))
have "(∀p'. strategy (g # hd (l @ [v]) # p') = s (hd (l @ [v]) # p'))" using A by simp
thus "l @ [v] ≠ [] ∧ (∀p'. strategy (g # hd (l @ [v]) # p') = s (hd (l @ [v]) # p')) " by auto
qed
show "(v ∈ attacker ⟶ lhd Ps = the (s (l @ [v])))"
proof
assume "v ∈ attacker"
hence "the (strategy (g#(l@[v]))) = lhd Ps" using A play_consistent_attacker_nonpos.simps
by (smt (verit) Cons_eq_appendI ‹Q s (LCons v Ps) l ∧ Ps ≠ LNil› lhd_LCons llist.distinct(1) ltl_simps(2))
have "s (l @ [v]) = strategy (g#(l@[v]))" using A
by (metis (no_types, lifting) hd_Cons_tl hd_append2 snoc_eq_iff_butlast)
thus "lhd Ps = the (s (l @ [v]))" using ‹the (strategy (g#(l@[v]))) = lhd Ps› by simp
qed
qed
qed
qed
hence "play_consistent_attacker_nonpos strat p []" using play_consistent_attacker_nonpos.simps
by (smt (verit) False ‹g ∉ attacker› ‹play_consistent_attacker_nonpos strategy (LCons g p) []› append_butlast_last_id butlast.simps(2) last_ConsL last_ConsR lhd_LCons lhd_LCons_ltl list.distinct(1) ltl_simps(2) play_consistent_attacker_nonpos_cons_simp tail)
thus ?thesis using Strat a_win by blast
qed
from this obtain s where S: "(nonpos_attacker_winning_strategy s (the (apply_w g (lhd p) e)) (lhd p)) ∧ play_consistent_attacker_nonpos s p []" by auto
have "valid_play p" using A
by (metis llist.distinct(1) ltl_simps(2) valid_play.simps)
hence "¬defender_wins_play (the (apply_w g (lhd p) e)) p" using S
by (metis False nonpos_attacker_winning_strategy.elims(2) lhd_LCons llist.collapse(1) not_lnull_conv)
hence P: "lfinite p ∧ (energy_level (the (apply_w g (lhd p) e)) p (the_enat (llength p)-1)) ≠ None ∧ ¬ ((llast p)∈ attacker ∧ deadend (llast p))"
using defender_wins_play_def by simp
hence "∃n. llength p = enat (Suc n)" using False
by (metis lfinite_llength_enat llength_eq_0 lnull_def old.nat.exhaust zero_enat_def)
from this obtain n where "llength p = enat (Suc n)" by auto
hence "llength (LCons g p) = enat (Suc (Suc n))"
by (simp add: eSuc_enat)
hence "Suc (the_enat (llength p)-1) = (the_enat (llength (LCons g p))-1)" using ‹llength p = enat (Suc n)› by simp
from ‹weight g (lhd p) ≠ None› have "(apply_w g (lhd p) e)≠ None"
by (simp add: all)
hence "energy_level (the (apply_w g (lhd p) e)) p (the_enat (llength p)-1) = energy_level e (LCons g p) (the_enat (llength (LCons g p))-1)"
using P energy_level_cons ‹Suc (the_enat (llength p)-1) = (the_enat (llength (LCons g p))-1)› A
by (metis (no_types, lifting) False ‹∃n. llength p = enat (Suc n)› diff_Suc_1 enat_ord_simps(2) lessI llist.collapse(1) the_enat.simps)
hence "(energy_level e (LCons g p) (the_enat (llength (LCons g p))-1)) ≠ None"
using P by simp
then show ?thesis using P
by (simp add: False energy_game.defender_wins_play_def llast_LCons lnull_def)
qed
qed
qed
show "nonpos_winning_budget e g" using nonpos_winning_budget.simps nonpos_attacker_winning_strategy.simps winning valid
by blast
qed
lemma winning_budget_ind_implies_nonpos:
assumes "winning_budget_ind e g"
shows "nonpos_winning_budget e g"
proof-
define f where "f = (λp x1 x2.
(∃g e. x1 = e ∧
x2 = g ∧
g ∉ attacker ∧
(∀g'. weight g g' ≠ None ⟶
apply_w g g' e ≠ None ∧ p (the (apply_w g g' e)) g')) ∨
(∃g e. x1 = e ∧
x2 = g ∧
g ∈ attacker ∧
(∃g'. weight g g' ≠ None ∧
apply_w g g' e ≠ None ∧ p (the (apply_w g g' e)) g')))"
have "f nonpos_winning_budget = nonpos_winning_budget"
unfolding f_def
proof
fix e0
show "(λx2. (∃g e. e0 = e ∧
x2 = g ∧
g ∉ attacker ∧
(∀g'. weight g g' ≠ None ⟶
apply_w g g' e ≠ None ∧
nonpos_winning_budget (the (apply_w g g' e)) g')) ∨
(∃g e. e0 = e ∧
x2 = g ∧
g ∈ attacker ∧
(∃g'. weight g g' ≠ None ∧
apply_w g g' e ≠ None ∧
nonpos_winning_budget (the (apply_w g g' e)) g'))) =
nonpos_winning_budget e0"
proof
fix g0
show "((∃g e. e0 = e ∧
g0 = g ∧
g ∉ attacker ∧
(∀g'. weight g g' ≠ None ⟶
apply_w g g' e ≠ None ∧
nonpos_winning_budget (the (apply_w g g' e)) g')) ∨
(∃g e. e0 = e ∧
g0 = g ∧
g ∈ attacker ∧
(∃g'. weight g g' ≠ None ∧
apply_w g g' e ≠ None ∧
nonpos_winning_budget (the (apply_w g g' e)) g'))) =
nonpos_winning_budget e0 g0"
proof
assume " (∃g e. e0 = e ∧
g0 = g ∧
g ∉ attacker ∧
(∀g'. weight g g' ≠ None ⟶
apply_w g g' e ≠ None ∧ nonpos_winning_budget (the (apply_w g g' e)) g')) ∨
(∃g e. e0 = e ∧
g0 = g ∧
g ∈ attacker ∧
(∃g'. weight g g' ≠ None ∧
apply_w g g' e ≠ None ∧ nonpos_winning_budget (the (apply_w g g' e)) g'))"
thus "nonpos_winning_budget e0 g0" using inductive_implies_nonpos_winning_budget
by blast
next
assume "nonpos_winning_budget e0 g0"
thus " (∃g e. e0 = e ∧
g0 = g ∧
g ∉ attacker ∧
(∀g'. weight g g' ≠ None ⟶
apply_w g g' e ≠ None ∧ nonpos_winning_budget (the (apply_w g g' e)) g')) ∨
(∃g e. e0 = e ∧
g0 = g ∧
g ∈ attacker ∧
(∃g'. weight g g' ≠ None ∧
apply_w g g' e ≠ None ∧ nonpos_winning_budget (the (apply_w g g' e)) g'))"
using nonpos_winning_budget_implies_inductive
by meson
qed
qed
qed
hence "lfp f ≤ nonpos_winning_budget "
using lfp_lowerbound
by (metis order_refl)
hence "winning_budget_ind ≤ nonpos_winning_budget"
using f_def HOL.nitpick_unfold(211) by simp
thus ?thesis using assms
by blast
qed
text‹Finally, we can state the inductive characterisation of attacker winning budgets assuming energy-positional determinacy.›
lemma inductive_winning_budget:
assumes "nonpos_winning_budget = winning_budget"
shows "winning_budget = winning_budget_ind"
proof
fix e
show "winning_budget e = winning_budget_ind e"
proof
fix g
show "winning_budget e g = winning_budget_ind e g"
proof
assume "winning_budget e g"
thus "winning_budget_ind e g"
using winning_budget_implies_ind winning_budget.simps by auto
next
assume "winning_budget_ind e g"
hence "nonpos_winning_budget e g"
using winning_budget_ind_implies_nonpos by simp
thus "winning_budget e g" using assms by simp
qed
qed
qed
end
end