Zulip Chat Archive

Stream: new members

Topic: Formalizing strategy problems


klh (Nov 01 2024 at 02:02):

image.png
I want to formalize its solution,but I can not even formalize the quesion itself.I just want to use lean to solve some strategy problems.Can someone help me illustrate this with lean4.

klh (Nov 01 2024 at 02:25):

image.png
The answer is easy,so I think its solution will be a good exercise for a beginner like me.The tough part is just the statement of the question itself :face_holding_back_tears:

Eric Wieser (Nov 01 2024 at 02:32):

It won't be smooth sailing, but maybe docs#SetTheory.PGame.State is a good tool here

Violeta Hernández (Nov 01 2024 at 03:51):

I don't think I'd be recommending the PGame API to any beginner. There's a lot of flaws with it in its current state...

Violeta Hernández (Nov 01 2024 at 03:52):

(no pun intended)

Violeta Hernández (Nov 01 2024 at 03:52):

That being said, I don't think we currently have any better mechanism to formalize questions like these.

Eric Wieser (Nov 01 2024 at 12:18):

I agree that this probably isn't very beginner friendly, but I think this would be a good exercise in finding and resolving painpoints in the PGame API, and hopefully you can get expert help from people like Violeta

Eric Wieser (Nov 01 2024 at 12:29):

I think this might be a correct statement?

import Mathlib

structure Garden (m n : Nat) where
  dandelions : Finset (Fin m × Fin n)
deriving DecidableEq

def Garden.mowRow (g : Garden m n) (i : Fin m) : Option (Garden m n) :=
  if i  g.dandelions.image (·.1) then
    some { dandelions := g.dandelions.filter (·.1  i) }
  else
    none

abbrev Garden.univ (m n : Nat) : Garden m n where dandelions := Finset.univ

instance : SetTheory.PGame.State (Garden m n) where
  turnBound g := g.dandelions.card
  l g := (Finset.univ.image g.mowRow).filterMap id fun _ _ _ hx hy => by aesop
  r g := sorry
  left_bound := sorry
  right_bound := sorry

example : {(m, n) | SetTheory.Game.ofState (Garden.univ m n) > 0 } = _ := sorry

David Renshaw (Nov 01 2024 at 15:08):

For this kind of problem, I have had success with a more direct encoding via inductives. (The austere abstractions of the PGame API scare me away).
Something like this should work:

import Mathlib.Tactic

inductive Player where
| Jana : Player
| Viviane : Player
deriving DecidableEq

def Player.other : Player  Player
| .Jana => Viviane
| .Viviane => Jana

structure State (m n : Nat) where
  dandelions : Finset (Fin m × Fin n)
  turn : Player
deriving DecidableEq

inductive Move (m n : Nat) where
| DeleteRow : Fin m  Move m n
| DeleteColumn : Fin n  Move m n
deriving DecidableEq

def Move.IsValid {m n : Nat} (s : State m n) : Move m n  Prop
| DeleteRow ii => ii  s.dandelions.image (·.1)
| DeleteColumn jj => jj  s.dandelions.image (·.2)

def make_move {m n : Nat} (s : State m n) : Move m n  State m n
| .DeleteRow ii => s.dandelions.filter (·.1  ii), s.turn.other
| .DeleteColumn jj => s.dandelions.filter (·.2  jj), s.turn.other

inductive HasForcedWin (m n : ) : Player  State m n  Prop where

-- If it's player p's turn and there is a valid move after which we can prove
-- `HasForcedWin p`, then `HasForcedWin p` holds on the initial state.
| Self (s : State m n) (mv : Move m n) : Move.IsValid s mv 
   HasForcedWin m n s.turn (make_move s mv) 
   HasForcedWin m n s.turn s

-- If it's player p's turn and all valid moves lead to states where
-- `HasForcedWin p.other` holds, then `HasForcedWin p.other` holds on
-- the initial state.
-- This case includes the end of game condition -- if there are no valid moves,
-- then the play whose turn it is has lost.
| Opponent (s : State m n) :
  ( mv, Move.IsValid s mv  HasForcedWin m n s.turn (make_move s mv)) 
   HasForcedWin m n s.turn.other s

abbrev JanaWinsSet : Set ( × ) := sorry

theorem problem1 (m n : ) :
    (m, n)  JanaWinsSet 
    HasForcedWin m n Player.Jana Finset.univ, Player.Jana := by
  sorry

klh (Nov 01 2024 at 15:57):

Eric Wieser 发言道

I think this might be a correct statement?

import Mathlib

structure Garden (m n : Nat) where
  dandelions : Finset (Fin m × Fin n)
deriving DecidableEq

def Garden.mowRow (g : Garden m n) (i : Fin m) : Option (Garden m n) :=
  if i  g.dandelions.image (·.1) then
    some { dandelions := g.dandelions.filter (·.1  i) }
  else
    none

abbrev Garden.univ (m n : Nat) : Garden m n where dandelions := Finset.univ

instance : SetTheory.PGame.State (Garden m n) where
  turnBound g := g.dandelions.card
  l g := (Finset.univ.image g.mowRow).filterMap id fun _ _ _ hx hy => by aesop
  r g := sorry
  left_bound := sorry
  right_bound := sorry

example : {(m, n) | SetTheory.Game.ofState (Garden.univ m n) > 0 } = _ := sorry

Thank you,this is a little difficult for me :face_holding_back_tears:

klh (Nov 01 2024 at 15:58):

David Renshaw 发言道

For this kind of problem, I have had success with a more direct encoding via inductives. (The austere abstractions of the PGame API scare me away).
Something like this should work:

import Mathlib.Tactic

inductive Player where
| Jana : Player
| Viviane : Player
deriving DecidableEq

def Player.other : Player  Player
| .Jana => Viviane
| .Viviane => Jana

structure State (m n : Nat) where
  dandelions : Finset (Fin m × Fin n)
  turn : Player
deriving DecidableEq

inductive Move (m n : Nat) where
| DeleteRow : Fin m  Move m n
| DeleteColumn : Fin n  Move m n
deriving DecidableEq

def Move.IsValid {m n : Nat} (s : State m n) : Move m n  Prop
| DeleteRow ii => ii  s.dandelions.image (·.1)
| DeleteColumn jj => jj  s.dandelions.image (·.2)

def make_move {m n : Nat} (s : State m n) : Move m n  State m n
| .DeleteRow ii => s.dandelions.filter (·.1  ii), s.turn.other
| .DeleteColumn jj => s.dandelions.filter (·.2  jj), s.turn.other

inductive HasForcedWin (m n : ) : Player  State m n  Prop where

-- If it's player p's turn and there is a valid move after which we can prove
-- `HasForcedWin p`, then `HasForcedWin p` holds on the initial state.
| Self (s : State m n) (mv : Move m n) : Move.IsValid s mv 
   HasForcedWin m n s.turn (make_move s mv) 
   HasForcedWin m n s.turn s

-- If it's player p's turn and all valid moves lead to states where
-- `HasForcedWin p.other` holds, then `HasForcedWin p.other` holds on
-- the initial state.
-- This case includes the end of game condition -- if there are no valid moves,
-- then the play whose turn it is has lost.
| Opponent (s : State m n) :
  ( mv, Move.IsValid s mv  HasForcedWin m n s.turn (make_move s mv)) 
   HasForcedWin m n s.turn.other s

abbrev JanaWinsSet : Set ( × ) := sorry

theorem problem1 (m n : ) :
    (m, n)  JanaWinsSet 
    HasForcedWin m n Player.Jana Finset.univ, Player.Jana := by
  sorry

Oh!Thank you

klh (Nov 01 2024 at 15:59):

David Renshaw 发言道

For this kind of problem, I have had success with a more direct encoding via inductives. (The austere abstractions of the PGame API scare me away).
Something like this should work:

import Mathlib.Tactic

inductive Player where
| Jana : Player
| Viviane : Player
deriving DecidableEq

def Player.other : Player  Player
| .Jana => Viviane
| .Viviane => Jana

structure State (m n : Nat) where
  dandelions : Finset (Fin m × Fin n)
  turn : Player
deriving DecidableEq

inductive Move (m n : Nat) where
| DeleteRow : Fin m  Move m n
| DeleteColumn : Fin n  Move m n
deriving DecidableEq

def Move.IsValid {m n : Nat} (s : State m n) : Move m n  Prop
| DeleteRow ii => ii  s.dandelions.image (·.1)
| DeleteColumn jj => jj  s.dandelions.image (·.2)

def make_move {m n : Nat} (s : State m n) : Move m n  State m n
| .DeleteRow ii => s.dandelions.filter (·.1  ii), s.turn.other
| .DeleteColumn jj => s.dandelions.filter (·.2  jj), s.turn.other

inductive HasForcedWin (m n : ) : Player  State m n  Prop where

-- If it's player p's turn and there is a valid move after which we can prove
-- `HasForcedWin p`, then `HasForcedWin p` holds on the initial state.
| Self (s : State m n) (mv : Move m n) : Move.IsValid s mv 
   HasForcedWin m n s.turn (make_move s mv) 
   HasForcedWin m n s.turn s

-- If it's player p's turn and all valid moves lead to states where
-- `HasForcedWin p.other` holds, then `HasForcedWin p.other` holds on
-- the initial state.
-- This case includes the end of game condition -- if there are no valid moves,
-- then the play whose turn it is has lost.
| Opponent (s : State m n) :
  ( mv, Move.IsValid s mv  HasForcedWin m n s.turn (make_move s mv)) 
   HasForcedWin m n s.turn.other s

abbrev JanaWinsSet : Set ( × ) := sorry

theorem problem1 (m n : ) :
    (m, n)  JanaWinsSet 
    HasForcedWin m n Player.Jana Finset.univ, Player.Jana := by
  sorry

image.pngWhat is wrong with the last line?

David Renshaw (Nov 01 2024 at 17:14):

is there anything farther down in the file?

David Renshaw (Nov 01 2024 at 17:15):

it might be failing to parse the next command and reporting the error there

klh (Nov 02 2024 at 04:21):

image.png
No,this is just the last line in my code.

David Renshaw (Nov 02 2024 at 14:23):

you might try restarting the lean server on that file

David Renshaw (Nov 02 2024 at 14:25):

If that doesn't work, please copy/paste your code here, rather than posting a screenshot. It's difficult to debug a screenshot.

David Renshaw (Nov 02 2024 at 14:25):

What Lean version are you using?


Last updated: May 02 2025 at 03:31 UTC