# Theory CS_Game_Delay

theory CS_Game_Delay
imports Coupled_Simulation Simple_Game
```section ‹Game for Coupled Similarity with Delay Formulation›

theory CS_Game_Delay
imports
Coupled_Simulation
Simple_Game
begin

subsection ‹The Coupled Simulation Preorder Game Using Delay Steps›

datatype ('s, 'a) cs_game_node =
AttackerNode 's 's |
DefenderStepNode 'a 's 's |
DefenderCouplingNode 's 's

fun (in lts_tau) cs_game_moves ::
‹('s, 'a) cs_game_node ⇒ ('s, 'a) cs_game_node ⇒ bool› where
simulation_visible_challenge:
‹cs_game_moves (AttackerNode p q) (DefenderStepNode a p1 q0) =
(¬tau a ∧ p ⟼a p1 ∧ q = q0)› |
simulation_internal_attacker_move:
‹cs_game_moves (AttackerNode p q) (AttackerNode p1 q0) =
(∃a. tau a ∧ p ⟼a p1 ∧ q = q0)› |
‹cs_game_moves (DefenderStepNode a p1 q0) (AttackerNode p11 q1) =
(q0 =⊳a q1 ∧ p1 = p11)› |
coupling_challenge:
‹cs_game_moves (AttackerNode p q) (DefenderCouplingNode p0 q0) =
(p = p0 ∧ q = q0)› |
‹cs_game_moves (DefenderCouplingNode p0 q0) (AttackerNode q1 p00) =
(p0 = p00 ∧ q0 ⟼* tau q1)› |
cs_game_moves_no_step:
‹cs_game_moves _ _ = False›

fun cs_game_defender_node :: ‹('s, 'a) cs_game_node ⇒ bool› where
‹cs_game_defender_node (AttackerNode _ _) = False› |
‹cs_game_defender_node (DefenderStepNode _ _ _) = True› |
‹cs_game_defender_node (DefenderCouplingNode _ _) = True›

locale cs_game =
lts_tau trans τ +
simple_game cs_game_moves cs_game_defender_node initial
for
trans :: ‹'s ⇒ 'a ⇒ 's ⇒ bool› and
τ :: ‹'a› and
initial :: ‹('s, 'a) cs_game_node›
begin

subsection ‹Coupled Simulation Implies Winning Strategy›

fun strategy_from_coupleddsim :: ‹('s ⇒ 's ⇒ bool) ⇒ ('s, 'a) cs_game_node strategy› where
‹strategy_from_coupleddsim R ((DefenderStepNode a p1 q0)#play) =
(AttackerNode p1 (SOME q1 . R p1 q1 ∧ q0 =⊳a q1))› |
‹strategy_from_coupleddsim R ((DefenderCouplingNode p0 q0)#play) =
(AttackerNode (SOME q1 . R q1 p0 ∧ q0 ⟼* tau q1) p0)› |
‹strategy_from_coupleddsim _ _ = undefined›

lemma defender_preceded_by_attacker:
assumes
‹n0 # play ∈ plays›
‹cs_game_defender_node n0›
‹initial = AttackerNode p0 q0›
shows ‹∃ p q . hd play = AttackerNode p q ∧ cs_game_moves (AttackerNode p q) n0› ‹play ≠ []›
proof -
have n0_not_init: ‹n0 ≠ initial› using assms(2,3) by auto
hence ‹cs_game_moves (hd play) n0› using assms(1)
by (metis list.sel(1) list.sel(3) plays.cases)
thus ‹∃p q. hd play = AttackerNode p q ∧ cs_game_moves (AttackerNode p q) n0› using assms(2)
by (metis cs_game_defender_node.elims(2,3) local.cs_game_moves_no_step(1,2,3,6))
show ‹play ≠ []› using n0_not_init assms(1) plays.cases by auto
qed

lemma defender_only_challenged_by_visible_actions:
assumes
‹initial = AttackerNode p0 q0›
‹(DefenderStepNode a p q) # play ∈ plays›
shows
‹¬tau a›
using assms defender_preceded_by_attacker
by fastforce

lemma strategy_from_coupleddsim_retains_coupledsim:
assumes
‹R p0 q0›
‹coupled_delay_simulation R›
‹initial = AttackerNode p0 q0›
‹play ∈ plays_for_strategy (strategy_from_coupleddsim R)›
shows
‹hd play = AttackerNode p q ⟹ R p q›
‹length play > 1 ⟹ hd (tl play) = AttackerNode p q ⟹ R p q›
using assms(4)
proof (induct arbitrary: p q rule: plays_for_strategy.induct[OF assms(4)])
case 1
fix p q
assume ‹hd [initial] = AttackerNode p q›
hence ‹p = p0› ‹q = q0› using assms(3) by auto
thus ‹R p q› using assms(1) by simp
next
case 1
fix p q
assume ‹1 < length [initial]›
hence False by auto
thus ‹R p q›  ..
next
case (2 n0 play)
hence n0play_is_play: ‹n0 # play ∈ plays› using strategy_plays_subset by blast
fix p q
assume subassms:
‹hd (strategy_from_coupleddsim R (n0 # play) # n0 # play) = AttackerNode p q›
‹strategy_from_coupleddsim R (n0 # play) # n0 # play
∈ plays_for_strategy (strategy_from_coupleddsim R)›
then obtain pi qi where
piqi_def: ‹hd (play) = AttackerNode pi qi›
‹cs_game_moves (AttackerNode pi qi) n0› ‹play ≠ []›
using defender_preceded_by_attacker[OF n0play_is_play `cs_game_defender_node n0` assms(3)]
by blast
hence ‹R pi qi› using 2(1,3) by simp
have ‹(∃ a . n0 = (DefenderStepNode a p qi) ∧ ¬ tau a ∧ pi ⟼a p)
∨ (n0 = (DefenderCouplingNode pi qi))›
using piqi_def(2) 2(4,5) subassms(1)
using cs_game_defender_node.elims(2) cs_game_moves.simps(1,3)
cs_game_moves.simps(4) list.sel(1)
by metis
thus ‹R p q›
proof safe
fix a
assume n0_def: ‹n0 = DefenderStepNode a p qi› ‹¬ tau a› ‹pi ⟼a p›
have ‹strategy_from_coupleddsim R (n0 # play) =
(AttackerNode p (SOME q1 . R p q1 ∧ qi =⊳a q1))›
unfolding n0_def(1) by auto
with subassms(1) have q_def: ‹q = (SOME q1. R p q1 ∧ qi =⊳a  q1)› by auto
have ‹∃ qii . R p qii ∧ qi =⊳a qii›
using n0_def(2,3) `R pi qi` `coupled_delay_simulation R`
unfolding coupled_delay_simulation_def delay_simulation_def by blast
from someI_ex[OF this] show ‹R p q› unfolding q_def by blast
next
assume n0_def: ‹n0 = DefenderCouplingNode pi qi›
have ‹strategy_from_coupleddsim R (n0 # play) =
(AttackerNode (SOME q1 . R q1 pi ∧ qi ⟼* tau q1) pi)›
unfolding n0_def(1) by auto
with subassms(1) have qp_def: ‹p = (SOME q1 . R q1 pi ∧ qi ⟼* tau q1)› ‹q = pi› by auto
have ‹∃ q1 . R q1 pi ∧ qi ⟼* tau q1›
using n0_def `R pi qi` `coupled_delay_simulation R`
unfolding coupled_delay_simulation_def by blast
from someI_ex[OF this] show ‹R p q› unfolding qp_def by blast
qed
next
case (2 n0 play)
fix p q
assume ‹hd (tl (strategy_from_coupleddsim R (n0 # play) # n0 # play)) = AttackerNode p q›
hence False using 2(4) by auto
thus ‹R p q› ..
next
case (3 n1 play n1')
fix p q
assume ‹hd (n1' # n1 # play) = AttackerNode p q›
then obtain p1 a where n1_spec: ‹n1 = AttackerNode p1 q› ‹p1 ⟼a p› ‹tau a›
using 3 unfolding player1_position_def list.sel(1)
by (metis cs_game_defender_node.elims(3) simulation_internal_attacker_move)
then have ‹R p1 q› using 3 by auto
thus ‹R p q›
using  n1_spec(2,3) ‹coupled_delay_simulation R›
unfolding coupled_delay_simulation_def delay_simulation_def by auto
next
case (3 n1 play n1')
fix p q
assume ‹hd (tl (n1' # n1 # play)) = AttackerNode p q›
thus ‹R p q› using 3(1,2) by auto
qed

lemma strategy_from_coupleddsim_sound:
assumes
‹R p0 q0›
‹coupled_delay_simulation R›
‹initial = AttackerNode p0 q0›
shows
‹sound_strategy (strategy_from_coupleddsim R)›
unfolding sound_strategy_def
proof clarify
fix n0 play
assume subassms:
‹n0 # play ∈ plays_for_strategy(strategy_from_coupleddsim R)›
‹cs_game_defender_node n0›
then obtain pi qi where
piqi_def: ‹hd (play) = AttackerNode pi qi›
‹cs_game_moves (AttackerNode pi qi) n0› ‹play ≠ []›
using defender_preceded_by_attacker[OF _ `cs_game_defender_node n0` assms(3)]
strategy_plays_subset by blast
hence ‹R pi qi›
using strategy_from_coupleddsim_retains_coupledsim[OF assms] list.sel subassms by auto
have ‹(∃ a p . n0 = (DefenderStepNode a p qi) ∧ pi ⟼a p)
∨ (n0 = (DefenderCouplingNode pi qi))›
by (metis cs_game_defender_node.elims(2)
coupling_challenge simulation_visible_challenge piqi_def(2) subassms(2))
thus ‹cs_game_moves n0 (strategy_from_coupleddsim R (n0 # play))›
proof safe
fix a p
assume dsn:
‹pi ⟼a  p›
‹n0 = DefenderStepNode a p qi›
hence qi_spec:
‹(strategy_from_coupleddsim R (n0 # play)) =
AttackerNode p (SOME q1 . R p q1 ∧ qi =⊳a q1)›
by simp
then obtain qii where qii_spec:
‹AttackerNode p (SOME q1 . R p q1 ∧ qi =⊳a q1) = AttackerNode p qii› by blast
have ‹∃ qii . R p qii ∧ qi =⊳a qii›
using dsn `R pi qi` `coupled_delay_simulation R` steps.refl
unfolding coupled_delay_simulation_def delay_simulation_def by blast
from someI_ex[OF this] have ‹R p qii ∧ qi =⊳a qii› using qii_spec by blast
thus ‹cs_game_moves (DefenderStepNode a p qi)
(strategy_from_coupleddsim R (DefenderStepNode a p qi # play))›
using qi_spec qii_spec unfolding dsn(2) by auto
next ―‹coupling quite analogous.›
assume dcn:
‹n0 = DefenderCouplingNode pi qi›
hence qi_spec:
‹(strategy_from_coupleddsim R (n0 # play)) =
AttackerNode (SOME q1 . R q1 pi ∧ qi ⟼* tau q1) pi›
by simp
then obtain qii where qii_spec:
‹AttackerNode (SOME q1 . R q1 pi ∧ qi ⟼* tau q1) pi = AttackerNode qii pi› by blast
have ‹∃ qii . R qii pi ∧ qi ⟼* tau qii›
using dcn `R pi qi` `coupled_delay_simulation R`
unfolding coupled_delay_simulation_def by blast
from someI_ex[OF this] have ‹R qii pi ∧ qi ⟼* tau qii› using qii_spec by blast
thus ‹cs_game_moves (DefenderCouplingNode pi qi)
(strategy_from_coupleddsim R (DefenderCouplingNode pi qi # play))›
using qi_spec qii_spec unfolding dcn by auto
qed
qed

lemma coupleddsim_implies_winning_strategy:
assumes
‹R p q›
‹coupled_delay_simulation R›
‹initial = AttackerNode p q›
shows
‹player0_winning_strategy (strategy_from_coupleddsim R)›
unfolding player0_winning_strategy_def
proof (clarify)
fix play
assume subassms:
‹play ∈ plays_for_strategy (strategy_from_coupleddsim R)›
‹player1_wins play›
show ‹False› using subassms
proof (induct rule: simple_game.plays_for_strategy.induct[OF subassms(1)])
case 1
then show ?case unfolding player1_wins_def using assms(3) by auto
next
case (2 n0 play)
hence ‹¬ cs_game_defender_node (strategy_from_coupleddsim R (n0 # play))›
using cs_game_moves_no_step cs_game_defender_node.elims(2) by metis
hence ‹¬  player1_wins (strategy_from_coupleddsim R (n0 # play) # n0 # play)›
unfolding player1_wins_def by auto
thus ?case using 2(6) by auto
next
case (3 n1 play n1')
then obtain p q where n1_def: ‹n1 = AttackerNode p q›
unfolding player1_position_def using cs_game_defender_node.elims(3) by blast
hence ‹R p q›
using strategy_from_coupleddsim_retains_coupledsim[OF assms, of ‹n1 # play›] 3(1) by auto
have ‹(∃ p1 a . n1' = (DefenderStepNode a p1 q) ∧ (p ⟼a p1))
∨ n1' = (DefenderCouplingNode p q)›
using n1_def `cs_game_moves n1 n1'` coupling_challenge cs_game_moves_no_step(5)
simulation_visible_challenge
by (metis cs_game_defender_node.elims(2) 3(6) list.sel(1) player1_wins_def)
then show ?case
proof
assume ‹(∃ p1 a . n1' = (DefenderStepNode a p1 q) ∧ (p ⟼a p1))›
then obtain p1 a where
n1'_def: ‹n1' = (DefenderStepNode a p1 q)› ‹p ⟼a p1›
by blast
hence ‹∃ q1 . q =⊳a q1›
using `R p q` `coupled_delay_simulation R`
unfolding coupled_delay_simulation_def delay_simulation_def by blast
hence ‹∃ q1 . cs_game_moves (DefenderStepNode a p1 q) (AttackerNode p1 q1)›
by auto
with `player1_wins (n1' # n1 # play)` show False unfolding player1_wins_def n1'_def
by (metis list.sel(1))
next
assume n1'_def: ‹n1' = DefenderCouplingNode p q›
have ‹∃ q1 . q ⟼*tau q1›
using `coupled_delay_simulation R` `R p q`
unfolding coupled_delay_simulation_def by blast
hence ‹∃ q1 . cs_game_moves (DefenderCouplingNode p q) (AttackerNode q1 p)›
by auto
with `player1_wins (n1' # n1 # play)` show False unfolding player1_wins_def n1'_def
by (metis list.sel(1))
qed
qed
qed

subsection ‹Winning Strategy Induces Coupled Simulation›

lemma winning_strategy_implies_coupleddsim:
assumes
‹player0_winning_strategy f›
‹sound_strategy f›
defines
‹R == λ p q . (∃ play ∈ plays_for_strategy f . hd play = AttackerNode p q)›
shows
‹coupled_delay_simulation R›
unfolding coupled_delay_simulation_def delay_simulation_def
proof safe
fix p q p' a
assume challenge:
‹R p q›
‹p ⟼a  p'›
‹tau a ›
hence game_move: ‹cs_game_moves (AttackerNode p q) (AttackerNode p' q)› by auto
have ‹(∃ play ∈ plays_for_strategy f . hd play = AttackerNode p q)›
using challenge(1) assms by blast
then obtain play where
play_spec: ‹AttackerNode p q # play ∈ plays_for_strategy f›
by (metis list.sel(1) simple_game.plays.cases strategy_plays_subset)
hence interplay: ‹(AttackerNode p' q) # AttackerNode p q # play ∈ plays_for_strategy f›
using game_move by (simp add: player1_position_def simple_game.plays_for_strategy.p1move)
then show ‹R p' q›
unfolding R_def list.sel by force
next
fix p q p' a
assume challenge:
‹R p q›
‹p ⟼a  p'›
‹¬ tau a ›
hence game_move: ‹cs_game_moves (AttackerNode p q) (DefenderStepNode a p' q)› by auto
have ‹(∃ play ∈ plays_for_strategy f . hd play = AttackerNode p q)›
using challenge(1) assms by blast
then obtain play where
play_spec: ‹AttackerNode p q # play ∈ plays_for_strategy f›
by (metis list.sel(1) simple_game.plays.cases strategy_plays_subset)
hence interplay: ‹(DefenderStepNode a p' q) # AttackerNode p q # play ∈ plays_for_strategy f›
using game_move by (simp add: player1_position_def simple_game.plays_for_strategy.p1move)
hence ‹¬ player1_wins ((DefenderStepNode a p' q) # AttackerNode p q # play)›
using assms(1) unfolding player0_winning_strategy_def by blast
then obtain n1 where n1_def:
‹n1 = f (DefenderStepNode a p' q # AttackerNode p q # play)›
‹cs_game_moves (DefenderStepNode a p' q) n1›
using interplay assms(2) unfolding player0_winning_strategy_def sound_strategy_def by simp
obtain q' where q'_spec:
‹(AttackerNode p' q') = n1› ‹q =⊳a q'›
using n1_def(2) by (cases n1, auto)
hence ‹(AttackerNode p' q') # (DefenderStepNode a p' q) # AttackerNode p q # play
∈ plays_for_strategy f›
using interplay n1_def by (simp add: simple_game.plays_for_strategy.p0move)
hence ‹R p' q'› unfolding R_def by (meson list.sel(1))
thus ‹∃q'. R p' q' ∧ q =⊳a  q'› using q'_spec(2) by blast
next
fix p q
assume challenge:
‹R p q›
hence game_move: ‹cs_game_moves (AttackerNode p q) (DefenderCouplingNode p q)› by auto
have ‹(∃ play ∈ plays_for_strategy f . hd play = AttackerNode p q)›
using challenge assms by blast
then obtain play where
play_spec: ‹AttackerNode p q # play ∈ plays_for_strategy f›
by (metis list.sel(1) simple_game.plays.cases strategy_plays_subset)
hence interplay: ‹(DefenderCouplingNode p q) # AttackerNode p q # play
∈ plays_for_strategy f›
using game_move by (simp add: player1_position_def simple_game.plays_for_strategy.p1move)
hence ‹¬ player1_wins ((DefenderCouplingNode p q) # AttackerNode p q # play)›
using assms(1) unfolding player0_winning_strategy_def by blast
then obtain n1 where n1_def:
‹n1 = f (DefenderCouplingNode p q # AttackerNode p q # play)›
‹cs_game_moves (DefenderCouplingNode p q) n1›
using interplay assms(2)
unfolding player0_winning_strategy_def sound_strategy_def by simp
obtain q' where q'_spec:
‹(AttackerNode q' p) = n1› ‹q ⟼* tau q'›
using n1_def(2) by (cases n1, auto)
hence ‹(AttackerNode q' p) # (DefenderCouplingNode p q) # AttackerNode p q # play
∈ plays_for_strategy f›
using interplay n1_def by (simp add: simple_game.plays_for_strategy.p0move)
hence ‹R q' p› unfolding R_def by (meson list.sel(1))
thus ‹∃q'. q ⟼* tau  q' ∧ R q' p› using q'_spec(2) by blast
qed

theorem winning_strategy_iff_coupledsim:
assumes
‹initial = AttackerNode p q›
shows
‹(∃ f . player0_winning_strategy f ∧ sound_strategy f)
= p ⊑cs q›
proof (rule)
assume
‹(∃f. player0_winning_strategy f ∧ sound_strategy f)›
then obtain f where
‹coupled_delay_simulation (λp q. ∃play∈plays_for_strategy f. hd play = AttackerNode p q)›
using winning_strategy_implies_coupleddsim by blast
moreover have ‹(λp q. ∃play∈plays_for_strategy f. hd play = AttackerNode p q) p q›
using assms plays_for_strategy.init[of f] by (meson list.sel(1))
ultimately show ‹p ⊑cs q›
unfolding coupled_sim_by_eq_coupled_delay_simulation
by (metis (mono_tags, lifting))
next
assume
‹p ⊑cs  q›
thus ‹(∃f. player0_winning_strategy f ∧ sound_strategy f)›
unfolding coupled_sim_by_eq_coupled_delay_simulation
using coupleddsim_implies_winning_strategy[OF _ _ assms]
strategy_from_coupleddsim_sound[OF _ _ assms] by blast
qed

end

end
```