File: Mathlib/SetTheory/Game/Basic.lean

full_name: SetTheory.Game
code: /-- The type of combinatorial games. In ZFC, a combinatorial game is constructed from
  two sets of combinatorial games that have been constructed at an earlier
  stage. To do this in type theory, we say that a combinatorial pre-game is built
  inductively from two families of combinatorial games indexed over any type
  in Type u. The resulting type `PGame.{u}` lives in `Type (u+1)`,
  reflecting that it is a proper class in ZFC.
  A combinatorial game is then constructed by quotienting by the equivalence
  `x ≈ y ↔ x ≤ y ∧ y ≤ x`. -/
abbrev Game 
goal: Type (u_1 + 1)

full_name: SetTheory.Game.instNeg
code: /-- Negation of games. -/
instance : Neg Game 
goal: Neg SetTheory.Game

full_name: SetTheory.Game.instZero
code: instance : Zero Game 
goal: Zero SetTheory.Game

full_name: SetTheory.Game.instAdd
code: instance : Add Game 
goal: Add SetTheory.Game

full_name: SetTheory.Game.instAddCommGroupWithOneGame
code: instance instAddCommGroupWithOneGame : AddCommGroupWithOne Game 
goal: AddCommGroupWithOne SetTheory.Game

full_name: SetTheory.Game.instInhabited
code: instance : Inhabited Game 
goal: Inhabited SetTheory.Game

full_name: SetTheory.Game.instPartialOrderGame
code: instance instPartialOrderGame : PartialOrder Game 
goal: PartialOrder SetTheory.Game

full_name: SetTheory.Game.LF
code: /-- The less or fuzzy relation on games.

If `0 ⧏ x` (less or fuzzy with), then Left can win `x` as the first player. -/
def LF : Game → Game → Prop 
goal: SetTheory.Game → SetTheory.Game → Prop

full_name: SetTheory.Game.«_aux_Mathlib_SetTheory_Game_Basic___macroRules_SetTheory_Game_term_⧏__1»
code: local infixl:50 " ⧏ " => LF
goal: Lean.Macro

full_name: SetTheory.Game._aux_Mathlib_SetTheory_Game_Basic___unexpand_SetTheory_Game_LF_1
code: local infixl:50 " ⧏ " => LF
goal: Lean.PrettyPrinter.Unexpander

full_name: SetTheory.Game.not_le
code: /-- On `Game`, simp-normal inequalities should use as few negations as possible. -/
@[simp]
theorem not_le : ∀ {x y : Game}, ¬x ≤ y ↔ y ⧏ x 
goal: ¬x ≤ y ↔ y.LF x

full_name: SetTheory.Game.not_lf
code: /-- On `Game`, simp-normal inequalities should use as few negations as possible. -/
@[simp]
theorem not_lf : ∀ {x y : Game}, ¬x ⧏ y ↔ y ≤ x 
goal: ¬x.LF y ↔ y ≤ x

full_name: SetTheory.Game.instIsTrichotomousLF
code: instance : IsTrichotomous Game LF 
goal: IsTrichotomous SetTheory.Game SetTheory.Game.LF

full_name: SetTheory.Game.PGame.le_iff_game_le
code: theorem PGame.le_iff_game_le {x y : PGame} : x ≤ y ↔ (⟦x⟧ : Game) ≤ ⟦y⟧ 
goal: x ≤ y ↔ ⟦x⟧ ≤ ⟦y⟧

full_name: SetTheory.Game.PGame.lf_iff_game_lf
code: theorem PGame.lf_iff_game_lf {x y : PGame} : PGame.LF x y ↔ ⟦x⟧ ⧏ ⟦y⟧ 
goal: x.LF y ↔ SetTheory.Game.LF ⟦x⟧ ⟦y⟧

full_name: SetTheory.Game.PGame.lt_iff_game_lt
code: theorem PGame.lt_iff_game_lt {x y : PGame} : x < y ↔ (⟦x⟧ : Game) < ⟦y⟧ 
goal: x < y ↔ ⟦x⟧ < ⟦y⟧

full_name: SetTheory.Game.PGame.equiv_iff_game_eq
code: theorem PGame.equiv_iff_game_eq {x y : PGame} : x ≈ y ↔ (⟦x⟧ : Game) = ⟦y⟧ 
goal: x ≈ y ↔ ⟦x⟧ = ⟦y⟧

full_name: SetTheory.Game.Fuzzy
code: /-- The fuzzy, confused, or incomparable relation on games.

If `x ‖ 0`, then the first player can always win `x`. -/
def Fuzzy : Game → Game → Prop 
goal: SetTheory.Game → SetTheory.Game → Prop

full_name: SetTheory.Game._aux_Mathlib_SetTheory_Game_Basic___unexpand_SetTheory_Game_Fuzzy_1
code: local infixl:50 " ‖ " => Fuzzy
goal: Lean.PrettyPrinter.Unexpander

full_name: SetTheory.Game.«_aux_Mathlib_SetTheory_Game_Basic___macroRules_SetTheory_Game_term_‖__1»
code: local infixl:50 " ‖ " => Fuzzy
goal: Lean.Macro

full_name: SetTheory.Game.PGame.fuzzy_iff_game_fuzzy
code: theorem PGame.fuzzy_iff_game_fuzzy {x y : PGame} : PGame.Fuzzy x y ↔ ⟦x⟧ ‖ ⟦y⟧ 
goal: x.Fuzzy y ↔ SetTheory.Game.Fuzzy ⟦x⟧ ⟦y⟧

full_name: SetTheory.Game.covariantClass_add_le
code: instance covariantClass_add_le : CovariantClass Game Game (· + ·) (· ≤ ·) 
goal: CovariantClass SetTheory.Game SetTheory.Game (fun x x_1 => x + x_1) fun x x_1 => x ≤ x_1

full_name: SetTheory.Game.covariantClass_swap_add_le
code: instance covariantClass_swap_add_le : CovariantClass Game Game (swap (· + ·)) (· ≤ ·) 
goal: CovariantClass SetTheory.Game SetTheory.Game (Function.swap fun x x_1 => x + x_1) fun x x_1 => x ≤ x_1

full_name: SetTheory.Game.covariantClass_add_lt
code: instance covariantClass_add_lt : CovariantClass Game Game (· + ·) (· < ·) 
goal: CovariantClass SetTheory.Game SetTheory.Game (fun x x_1 => x + x_1) fun x x_1 => x < x_1

full_name: SetTheory.Game.covariantClass_swap_add_lt
code: instance covariantClass_swap_add_lt : CovariantClass Game Game (swap (· + ·)) (· < ·) 
goal: CovariantClass SetTheory.Game SetTheory.Game (Function.swap fun x x_1 => x + x_1) fun x x_1 => x < x_1

full_name: SetTheory.Game.add_lf_add_right
code: theorem add_lf_add_right : ∀ {b c : Game} (_ : b ⧏ c) (a), (b + a : Game) ⧏ c + a 
goal: b.LF c → ∀ (a : SetTheory.Game), (b + a).LF (c + a)

full_name: SetTheory.Game.add_lf_add_left
code: theorem add_lf_add_left : ∀ {b c : Game} (_ : b ⧏ c) (a), (a + b : Game) ⧏ a + c 
goal: b.LF c → ∀ (a : SetTheory.Game), (a + b).LF (a + c)

full_name: SetTheory.Game.orderedAddCommGroup
code: instance orderedAddCommGroup : OrderedAddCommGroup Game 
goal: OrderedAddCommGroup SetTheory.Game

full_name: SetTheory.Game.bddAbove_range_of_small
code: /-- A small family of games is bounded above. -/
lemma bddAbove_range_of_small {ι : Type*} [Small.{u} ι] (f : ι → Game.{u}) :
    BddAbove (Set.range f) 
goal: BddAbove (Set.range f)

full_name: SetTheory.Game.bddAbove_of_small
code: /-- A small set of games is bounded above. -/
lemma bddAbove_of_small (s : Set Game.{u}) [Small.{u} s] : BddAbove s 
goal: BddAbove s

full_name: SetTheory.Game.bddBelow_range_of_small
code: /-- A small family of games is bounded below. -/
lemma bddBelow_range_of_small {ι : Type*} [Small.{u} ι] (f : ι → Game.{u}) :
    BddBelow (Set.range f) 
goal: BddBelow (Set.range f)

full_name: SetTheory.Game.bddBelow_of_small
code: /-- A small set of games is bounded below. -/
lemma bddBelow_of_small (s : Set Game.{u}) [Small.{u} s] : BddBelow s 
goal: BddBelow s

full_name: SetTheory.PGame.quot_neg
code: @[simp]
theorem quot_neg (a : PGame) : (⟦-a⟧ : Game) = -⟦a⟧ 
goal: ⟦-a⟧ = -⟦a⟧

full_name: SetTheory.PGame.quot_add
code: @[simp]
theorem quot_add (a b : PGame) : ⟦a + b⟧ = (⟦a⟧ : Game) + ⟦b⟧ 
goal: ⟦a + b⟧ = ⟦a⟧ + ⟦b⟧

full_name: SetTheory.PGame.quot_sub
code: @[simp]
theorem quot_sub (a b : PGame) : ⟦a - b⟧ = (⟦a⟧ : Game) - ⟦b⟧ 
goal: ⟦a - b⟧ = ⟦a⟧ - ⟦b⟧

full_name: SetTheory.PGame.quot_eq_of_mk'_quot_eq
code: theorem quot_eq_of_mk'_quot_eq {x y : PGame} (L : x.LeftMoves ≃ y.LeftMoves)
    (R : x.RightMoves ≃ y.RightMoves) (hl : ∀ i, (⟦x.moveLeft i⟧ : Game) = ⟦y.moveLeft (L i)⟧)
    (hr : ∀ j, (⟦x.moveRight j⟧ : Game) = ⟦y.moveRight (R j)⟧) : (⟦x⟧ : Game) = ⟦y⟧ 
goal: ⟦x⟧ = ⟦y⟧

full_name: SetTheory.PGame.instMul
code: /-- The product of `x = {xL | xR}` and `y = {yL | yR}` is
`{xL*y + x*yL - xL*yL, xR*y + x*yR - xR*yR | xL*y + x*yR - xL*yR, x*yL + xR*y - xR*yL }`. -/
instance : Mul PGame.{u} 
goal: Mul SetTheory.PGame

full_name: SetTheory.PGame.leftMoves_mul
code: theorem leftMoves_mul :
    ∀ x y : PGame.{u},
      (x * y).LeftMoves = (x.LeftMoves × y.LeftMoves ⊕ x.RightMoves × y.RightMoves)
  
goal: (x * y).LeftMoves = (x.LeftMoves × y.LeftMoves ⊕ x.RightMoves × y.RightMoves)

full_name: SetTheory.PGame.rightMoves_mul
code: theorem rightMoves_mul :
    ∀ x y : PGame.{u},
      (x * y).RightMoves = (x.LeftMoves × y.RightMoves ⊕ x.RightMoves × y.LeftMoves)
  
goal: (x * y).RightMoves = (x.LeftMoves × y.RightMoves ⊕ x.RightMoves × y.LeftMoves)

full_name: SetTheory.PGame.toLeftMovesMul
code: /-- Turns two left or right moves for `x` and `y` into a left move for `x * y` and vice versa.

Even though these types are the same (not definitionally so), this is the preferred way to convert
between them. -/
def toLeftMovesMul {x y : PGame} :
    (x.LeftMoves × y.LeftMoves) ⊕ (x.RightMoves × y.RightMoves) ≃ (x * y).LeftMoves 
goal: x.LeftMoves × y.LeftMoves ⊕ x.RightMoves × y.RightMoves ≃ (x * y).LeftMoves

full_name: SetTheory.PGame.toRightMovesMul
code: /-- Turns a left and a right move for `x` and `y` into a right move for `x * y` and vice versa.

Even though these types are the same (not definitionally so), this is the preferred way to convert
between them. -/
def toRightMovesMul {x y : PGame} :
    (x.LeftMoves × y.RightMoves) ⊕ (x.RightMoves × y.LeftMoves) ≃ (x * y).RightMoves 
goal: x.LeftMoves × y.RightMoves ⊕ x.RightMoves × y.LeftMoves ≃ (x * y).RightMoves

full_name: SetTheory.PGame.mk_mul_moveLeft_inl
code: @[simp]
theorem mk_mul_moveLeft_inl {xl xr yl yr} {xL xR yL yR} {i j} :
    (mk xl xr xL xR * mk yl yr yL yR).moveLeft (Sum.inl (i, j)) =
      xL i * mk yl yr yL yR + mk xl xr xL xR * yL j - xL i * yL j 
goal: (SetTheory.PGame.mk xl xr xL xR * SetTheory.PGame.mk yl yr yL yR).moveLeft (Sum.inl (i, j)) =
  xL i * SetTheory.PGame.mk yl yr yL yR + SetTheory.PGame.mk xl xr xL xR * yL j - xL i * yL j

full_name: SetTheory.PGame.mul_moveLeft_inl
code: @[simp]
theorem mul_moveLeft_inl {x y : PGame} {i j} :
    (x * y).moveLeft (toLeftMovesMul (Sum.inl (i, j))) =
      x.moveLeft i * y + x * y.moveLeft j - x.moveLeft i * y.moveLeft j 
goal: (x * y).moveLeft (SetTheory.PGame.toLeftMovesMul (Sum.inl (i, j))) =
  x.moveLeft i * y + x * y.moveLeft j - x.moveLeft i * y.moveLeft j

full_name: SetTheory.PGame.mk_mul_moveLeft_inr
code: @[simp]
theorem mk_mul_moveLeft_inr {xl xr yl yr} {xL xR yL yR} {i j} :
    (mk xl xr xL xR * mk yl yr yL yR).moveLeft (Sum.inr (i, j)) =
      xR i * mk yl yr yL yR + mk xl xr xL xR * yR j - xR i * yR j 
goal: (SetTheory.PGame.mk xl xr xL xR * SetTheory.PGame.mk yl yr yL yR).moveLeft (Sum.inr (i, j)) =
  xR i * SetTheory.PGame.mk yl yr yL yR + SetTheory.PGame.mk xl xr xL xR * yR j - xR i * yR j

full_name: SetTheory.PGame.mul_moveLeft_inr
code: @[simp]
theorem mul_moveLeft_inr {x y : PGame} {i j} :
    (x * y).moveLeft (toLeftMovesMul (Sum.inr (i, j))) =
      x.moveRight i * y + x * y.moveRight j - x.moveRight i * y.moveRight j 
goal: (x * y).moveLeft (SetTheory.PGame.toLeftMovesMul (Sum.inr (i, j))) =
  x.moveRight i * y + x * y.moveRight j - x.moveRight i * y.moveRight j

full_name: SetTheory.PGame.mk_mul_moveRight_inl
code: @[simp]
theorem mk_mul_moveRight_inl {xl xr yl yr} {xL xR yL yR} {i j} :
    (mk xl xr xL xR * mk yl yr yL yR).moveRight (Sum.inl (i, j)) =
      xL i * mk yl yr yL yR + mk xl xr xL xR * yR j - xL i * yR j 
goal: (SetTheory.PGame.mk xl xr xL xR * SetTheory.PGame.mk yl yr yL yR).moveRight (Sum.inl (i, j)) =
  xL i * SetTheory.PGame.mk yl yr yL yR + SetTheory.PGame.mk xl xr xL xR * yR j - xL i * yR j

full_name: SetTheory.PGame.mul_moveRight_inl
code: @[simp]
theorem mul_moveRight_inl {x y : PGame} {i j} :
    (x * y).moveRight (toRightMovesMul (Sum.inl (i, j))) =
      x.moveLeft i * y + x * y.moveRight j - x.moveLeft i * y.moveRight j 
goal: (x * y).moveRight (SetTheory.PGame.toRightMovesMul (Sum.inl (i, j))) =
  x.moveLeft i * y + x * y.moveRight j - x.moveLeft i * y.moveRight j

full_name: SetTheory.PGame.mk_mul_moveRight_inr
code: @[simp]
theorem mk_mul_moveRight_inr {xl xr yl yr} {xL xR yL yR} {i j} :
    (mk xl xr xL xR * mk yl yr yL yR).moveRight (Sum.inr (i, j)) =
      xR i * mk yl yr yL yR + mk xl xr xL xR * yL j - xR i * yL j 
goal: (SetTheory.PGame.mk xl xr xL xR * SetTheory.PGame.mk yl yr yL yR).moveRight (Sum.inr (i, j)) =
  xR i * SetTheory.PGame.mk yl yr yL yR + SetTheory.PGame.mk xl xr xL xR * yL j - xR i * yL j

full_name: SetTheory.PGame.mul_moveRight_inr
code: @[simp]
theorem mul_moveRight_inr {x y : PGame} {i j} :
    (x * y).moveRight (toRightMovesMul (Sum.inr (i, j))) =
      x.moveRight i * y + x * y.moveLeft j - x.moveRight i * y.moveLeft j 
goal: (x * y).moveRight (SetTheory.PGame.toRightMovesMul (Sum.inr (i, j))) =
  x.moveRight i * y + x * y.moveLeft j - x.moveRight i * y.moveLeft j

full_name: SetTheory.PGame.neg_mk_mul_moveLeft_inl
code: theorem neg_mk_mul_moveLeft_inl {xl xr yl yr} {xL xR yL yR} {i j} :
    (-(mk xl xr xL xR * mk yl yr yL yR)).moveLeft (Sum.inl (i, j)) =
      -(xL i * mk yl yr yL yR + mk xl xr xL xR * yR j - xL i * yR j) 
goal: (-(SetTheory.PGame.mk xl xr xL xR * SetTheory.PGame.mk yl yr yL yR)).moveLeft (Sum.inl (i, j)) =
  -(xL i * SetTheory.PGame.mk yl yr yL yR + SetTheory.PGame.mk xl xr xL xR * yR j - xL i * yR j)

full_name: SetTheory.PGame.neg_mk_mul_moveLeft_inr
code: theorem neg_mk_mul_moveLeft_inr {xl xr yl yr} {xL xR yL yR} {i j} :
    (-(mk xl xr xL xR * mk yl yr yL yR)).moveLeft (Sum.inr (i, j)) =
      -(xR i * mk yl yr yL yR + mk xl xr xL xR * yL j - xR i * yL j) 
goal: (-(SetTheory.PGame.mk xl xr xL xR * SetTheory.PGame.mk yl yr yL yR)).moveLeft (Sum.inr (i, j)) =
  -(xR i * SetTheory.PGame.mk yl yr yL yR + SetTheory.PGame.mk xl xr xL xR * yL j - xR i * yL j)

full_name: SetTheory.PGame.neg_mk_mul_moveRight_inl
code: theorem neg_mk_mul_moveRight_inl {xl xr yl yr} {xL xR yL yR} {i j} :
    (-(mk xl xr xL xR * mk yl yr yL yR)).moveRight (Sum.inl (i, j)) =
      -(xL i * mk yl yr yL yR + mk xl xr xL xR * yL j - xL i * yL j) 
goal: (-(SetTheory.PGame.mk xl xr xL xR * SetTheory.PGame.mk yl yr yL yR)).moveRight (Sum.inl (i, j)) =
  -(xL i * SetTheory.PGame.mk yl yr yL yR + SetTheory.PGame.mk xl xr xL xR * yL j - xL i * yL j)

full_name: SetTheory.PGame.neg_mk_mul_moveRight_inr
code: theorem neg_mk_mul_moveRight_inr {xl xr yl yr} {xL xR yL yR} {i j} :
    (-(mk xl xr xL xR * mk yl yr yL yR)).moveRight (Sum.inr (i, j)) =
      -(xR i * mk yl yr yL yR + mk xl xr xL xR * yR j - xR i * yR j) 
goal: (-(SetTheory.PGame.mk xl xr xL xR * SetTheory.PGame.mk yl yr yL yR)).moveRight (Sum.inr (i, j)) =
  -(xR i * SetTheory.PGame.mk yl yr yL yR + SetTheory.PGame.mk xl xr xL xR * yR j - xR i * yR j)

full_name: SetTheory.PGame.leftMoves_mul_cases
code: theorem leftMoves_mul_cases {x y : PGame} (k) {P : (x * y).LeftMoves → Prop}
    (hl : ∀ ix iy, P <| toLeftMovesMul (Sum.inl ⟨ix, iy⟩))
    (hr : ∀ jx jy, P <| toLeftMovesMul (Sum.inr ⟨jx, jy⟩)) : P k 
goal: P k

full_name: SetTheory.PGame.rightMoves_mul_cases
code: theorem rightMoves_mul_cases {x y : PGame} (k) {P : (x * y).RightMoves → Prop}
    (hl : ∀ ix jy, P <| toRightMovesMul (Sum.inl ⟨ix, jy⟩))
    (hr : ∀ jx iy, P <| toRightMovesMul (Sum.inr ⟨jx, iy⟩)) : P k 
goal: P k

full_name: SetTheory.PGame.mulCommRelabelling
code: /-- `x * y` and `y * x` have the same moves. -/
def mulCommRelabelling (x y : PGame.{u}) : x * y ≡r y * x 
goal: (x * y).Relabelling (y * x)

full_name: SetTheory.PGame.quot_mul_comm
code: theorem quot_mul_comm (x y : PGame.{u}) : (⟦x * y⟧ : Game) = ⟦y * x⟧ 
goal: ⟦x * y⟧ = ⟦y * x⟧

full_name: SetTheory.PGame.mul_comm_equiv
code: /-- `x * y` is equivalent to `y * x`. -/
theorem mul_comm_equiv (x y : PGame) : x * y ≈ y * x 
goal: x * y ≈ y * x

full_name: SetTheory.PGame.isEmpty_mul_zero_leftMoves
code: instance isEmpty_mul_zero_leftMoves (x : PGame.{u}) : IsEmpty (x * 0).LeftMoves 
goal: IsEmpty (x * 0).LeftMoves

full_name: SetTheory.PGame.isEmpty_mul_zero_rightMoves
code: instance isEmpty_mul_zero_rightMoves (x : PGame.{u}) : IsEmpty (x * 0).RightMoves 
goal: IsEmpty (x * 0).RightMoves

full_name: SetTheory.PGame.isEmpty_zero_mul_leftMoves
code: instance isEmpty_zero_mul_leftMoves (x : PGame.{u}) : IsEmpty (0 * x).LeftMoves 
goal: IsEmpty (0 * x).LeftMoves

full_name: SetTheory.PGame.isEmpty_zero_mul_rightMoves
code: instance isEmpty_zero_mul_rightMoves (x : PGame.{u}) : IsEmpty (0 * x).RightMoves 
goal: IsEmpty (0 * x).RightMoves

full_name: SetTheory.PGame.mulZeroRelabelling
code: /-- `x * 0` has exactly the same moves as `0`. -/
def mulZeroRelabelling (x : PGame) : x * 0 ≡r 0 
goal: (x * 0).Relabelling 0

full_name: SetTheory.PGame.mul_zero_equiv
code: /-- `x * 0` is equivalent to `0`. -/
theorem mul_zero_equiv (x : PGame) : x * 0 ≈ 0 
goal: x * 0 ≈ 0

full_name: SetTheory.PGame.quot_mul_zero
code: @[simp]
theorem quot_mul_zero (x : PGame) : (⟦x * 0⟧ : Game) = ⟦0⟧ 
goal: ⟦x * 0⟧ = ⟦0⟧

full_name: SetTheory.PGame.zeroMulRelabelling
code: /-- `0 * x` has exactly the same moves as `0`. -/
def zeroMulRelabelling (x : PGame) : 0 * x ≡r 0 
goal: (0 * x).Relabelling 0

full_name: SetTheory.PGame.zero_mul_equiv
code: /-- `0 * x` is equivalent to `0`. -/
theorem zero_mul_equiv (x : PGame) : 0 * x ≈ 0 
goal: 0 * x ≈ 0

full_name: SetTheory.PGame.quot_zero_mul
code: @[simp]
theorem quot_zero_mul (x : PGame) : (⟦0 * x⟧ : Game) = ⟦0⟧ 
goal: ⟦0 * x⟧ = ⟦0⟧

full_name: SetTheory.PGame.negMulRelabelling
code: /-- `-x * y` and `-(x * y)` have the same moves. -/
def negMulRelabelling (x y : PGame.{u}) : -x * y ≡r -(x * y) 
goal: (-x * y).Relabelling (-(x * y))

full_name: SetTheory.PGame.quot_neg_mul
code: @[simp]
theorem quot_neg_mul (x y : PGame) : (⟦-x * y⟧ : Game) = -⟦x * y⟧ 
goal: ⟦-x * y⟧ = -⟦x * y⟧

full_name: SetTheory.PGame.mulNegRelabelling
code: /-- `x * -y` and `-(x * y)` have the same moves. -/
def mulNegRelabelling (x y : PGame) : x * -y ≡r -(x * y) 
goal: (x * -y).Relabelling (-(x * y))

full_name: SetTheory.PGame.quot_mul_neg
code: @[simp]
theorem quot_mul_neg (x y : PGame) : ⟦x * -y⟧ = (-⟦x * y⟧ : Game) 
goal: ⟦x * -y⟧ = -⟦x * y⟧

full_name: SetTheory.PGame.quot_neg_mul_neg
code: theorem quot_neg_mul_neg (x y : PGame) : ⟦-x * -y⟧ = (⟦x * y⟧ : Game) 
goal: ⟦-x * -y⟧ = ⟦x * y⟧

full_name: SetTheory.PGame.quot_left_distrib
code: @[simp]
theorem quot_left_distrib (x y z : PGame) : (⟦x * (y + z)⟧ : Game) = ⟦x * y⟧ + ⟦x * z⟧ 
goal: ⟦x * (y + z)⟧ = ⟦x * y⟧ + ⟦x * z⟧

full_name: SetTheory.PGame.left_distrib_equiv
code: /-- `x * (y + z)` is equivalent to `x * y + x * z.`-/
theorem left_distrib_equiv (x y z : PGame) : x * (y + z) ≈ x * y + x * z 
goal: x * (y + z) ≈ x * y + x * z

full_name: SetTheory.PGame.quot_left_distrib_sub
code: @[simp]
theorem quot_left_distrib_sub (x y z : PGame) : (⟦x * (y - z)⟧ : Game) = ⟦x * y⟧ - ⟦x * z⟧ 
goal: ⟦x * (y - z)⟧ = ⟦x * y⟧ - ⟦x * z⟧

full_name: SetTheory.PGame.quot_right_distrib
code: @[simp]
theorem quot_right_distrib (x y z : PGame) : (⟦(x + y) * z⟧ : Game) = ⟦x * z⟧ + ⟦y * z⟧ 
goal: ⟦(x + y) * z⟧ = ⟦x * z⟧ + ⟦y * z⟧

full_name: SetTheory.PGame.right_distrib_equiv
code: /-- `(x + y) * z` is equivalent to `x * z + y * z.`-/
theorem right_distrib_equiv (x y z : PGame) : (x + y) * z ≈ x * z + y * z 
goal: (x + y) * z ≈ x * z + y * z

full_name: SetTheory.PGame.quot_right_distrib_sub
code: @[simp]
theorem quot_right_distrib_sub (x y z : PGame) : (⟦(y - z) * x⟧ : Game) = ⟦y * x⟧ - ⟦z * x⟧ 
goal: ⟦(y - z) * x⟧ = ⟦y * x⟧ - ⟦z * x⟧

full_name: SetTheory.PGame.mulOneRelabelling
code: /-- `x * 1` has the same moves as `x`. -/
def mulOneRelabelling : ∀ x : PGame.{u}, x * 1 ≡r x
  
goal: (x * 1).Relabelling x

full_name: SetTheory.PGame.quot_mul_one
code: @[simp]
theorem quot_mul_one (x : PGame) : (⟦x * 1⟧ : Game) = ⟦x⟧ 
goal: ⟦x * 1⟧ = ⟦x⟧

full_name: SetTheory.PGame.mul_one_equiv
code: /-- `x * 1` is equivalent to `x`. -/
theorem mul_one_equiv (x : PGame) : x * 1 ≈ x 
goal: x * 1 ≈ x

full_name: SetTheory.PGame.oneMulRelabelling
code: /-- `1 * x` has the same moves as `x`. -/
def oneMulRelabelling (x : PGame) : 1 * x ≡r x 
goal: (1 * x).Relabelling x

full_name: SetTheory.PGame.quot_one_mul
code: @[simp]
theorem quot_one_mul (x : PGame) : (⟦1 * x⟧ : Game) = ⟦x⟧ 
goal: ⟦1 * x⟧ = ⟦x⟧

full_name: SetTheory.PGame.one_mul_equiv
code: /-- `1 * x` is equivalent to `x`. -/
theorem one_mul_equiv (x : PGame) : 1 * x ≈ x 
goal: 1 * x ≈ x

full_name: SetTheory.PGame.quot_mul_assoc
code: theorem quot_mul_assoc (x y z : PGame) : (⟦x * y * z⟧ : Game) = ⟦x * (y * z)⟧ 
goal: ⟦x * y * z⟧ = ⟦x * (y * z)⟧

full_name: SetTheory.PGame.mul_assoc_equiv
code: /-- `x * y * z` is equivalent to `x * (y * z).`-/
theorem mul_assoc_equiv (x y z : PGame) : x * y * z ≈ x * (y * z) 
goal: x * y * z ≈ x * (y * z)

full_name: SetTheory.PGame.mulOption
code: /-- The left options of `x * y` of the first kind, i.e. of the form `xL * y + x * yL - xL * yL`. -/
def mulOption (x y : PGame) (i : LeftMoves x) (j : LeftMoves y) : PGame 
goal: SetTheory.PGame

full_name: SetTheory.PGame.mulOption_neg_neg
code: /-- Any left option of `x * y` of the first kind is also a left option of `x * -(-y)` of
  the first kind. -/
lemma mulOption_neg_neg {x} (y) {i j} :
    mulOption x y i j = mulOption x (-(-y)) i (toLeftMovesNeg <| toRightMovesNeg j) 
goal: x.mulOption y i j = x.mulOption (- -y) i (SetTheory.PGame.toLeftMovesNeg (SetTheory.PGame.toRightMovesNeg j))

full_name: SetTheory.PGame.mulOption_symm
code: /-- The left options of `x * y` agree with that of `y * x` up to equivalence. -/
lemma mulOption_symm (x y) {i j} : ⟦mulOption x y i j⟧ = (⟦mulOption y x j i⟧ : Game) 
goal: ⟦x.mulOption y i j⟧ = ⟦y.mulOption x j i⟧

full_name: SetTheory.PGame.leftMoves_mul_iff
code: /-- The left options of `x * y` of the second kind are the left options of `(-x) * (-y)` of the
  first kind, up to equivalence. -/
lemma leftMoves_mul_iff {x y : PGame} (P : Game → Prop) :
    (∀ k, P ⟦(x * y).moveLeft k⟧) ↔
    (∀ i j, P ⟦mulOption x y i j⟧) ∧ (∀ i j, P ⟦mulOption (-x) (-y) i j⟧) 
goal: (∀ (k : (x * y).LeftMoves), P ⟦(x * y).moveLeft k⟧) ↔
  (∀ (i : x.LeftMoves) (j : y.LeftMoves), P ⟦x.mulOption y i j⟧) ∧
    ∀ (i : (-x).LeftMoves) (j : (-y).LeftMoves), P ⟦(-x).mulOption (-y) i j⟧

full_name: SetTheory.PGame.rightMoves_mul_iff
code: /-- The right options of `x * y` are the left options of `x * (-y)` and of `(-x) * y` of the first
  kind, up to equivalence. -/
lemma rightMoves_mul_iff {x y : PGame} (P : Game → Prop) :
    (∀ k, P ⟦(x * y).moveRight k⟧) ↔
    (∀ i j, P (-⟦mulOption x (-y) i j⟧)) ∧ (∀ i j, P (-⟦mulOption (-x) y i j⟧)) 
goal: (∀ (k : (x * y).RightMoves), P ⟦(x * y).moveRight k⟧) ↔
  (∀ (i : x.LeftMoves) (j : (-y).LeftMoves), P (-⟦x.mulOption (-y) i j⟧)) ∧
    ∀ (i : (-x).LeftMoves) (j : y.LeftMoves), P (-⟦(-x).mulOption y i j⟧)

full_name: SetTheory.PGame.InvTy.right₂
code: /-- Because the two halves of the definition of `inv` produce more elements
on each side, we have to define the two families inductively.
This is the indexing set for the function, and `invVal` is the function part. -/
inductive InvTy (l r : Type u) : Bool → Type u
  | zero : InvTy l r false
  | left₁ : r → InvTy l r false → InvTy l r false
  | left₂ : l → InvTy l r true → InvTy l r false
  | right₁ : l → InvTy l r false → InvTy l r true
  | right₂ : r → InvTy l r true → InvTy l r true
goal: r → SetTheory.PGame.InvTy l r true → SetTheory.PGame.InvTy l r true

full_name: SetTheory.PGame.InvTy.left₂
code: /-- Because the two halves of the definition of `inv` produce more elements
on each side, we have to define the two families inductively.
This is the indexing set for the function, and `invVal` is the function part. -/
inductive InvTy (l r : Type u) : Bool → Type u
  | zero : InvTy l r false
  | left₁ : r → InvTy l r false → InvTy l r false
  | left₂ : l → InvTy l r true → InvTy l r false
  | right₁ : l → InvTy l r false → InvTy l r true
  | right₂ : r → InvTy l r true → InvTy l r true
goal: l → SetTheory.PGame.InvTy l r true → SetTheory.PGame.InvTy l r false

full_name: SetTheory.PGame.InvTy.right₁
code: /-- Because the two halves of the definition of `inv` produce more elements
on each side, we have to define the two families inductively.
This is the indexing set for the function, and `invVal` is the function part. -/
inductive InvTy (l r : Type u) : Bool → Type u
  | zero : InvTy l r false
  | left₁ : r → InvTy l r false → InvTy l r false
  | left₂ : l → InvTy l r true → InvTy l r false
  | right₁ : l → InvTy l r false → InvTy l r true
  | right₂ : r → InvTy l r true → InvTy l r true
goal: l → SetTheory.PGame.InvTy l r false → SetTheory.PGame.InvTy l r true

full_name: SetTheory.PGame.InvTy
code: /-- Because the two halves of the definition of `inv` produce more elements
on each side, we have to define the two families inductively.
This is the indexing set for the function, and `invVal` is the function part. -/
inductive InvTy (l r : Type u) : Bool → Type u
  | zero : InvTy l r false
  | left₁ : r → InvTy l r false → InvTy l r false
  | left₂ : l → InvTy l r true → InvTy l r false
  | right₁ : l → InvTy l r false → InvTy l r true
  | right₂ : r → InvTy l r true → InvTy l r true
goal: Bool → Type u

full_name: SetTheory.PGame.InvTy.zero
code: /-- Because the two halves of the definition of `inv` produce more elements
on each side, we have to define the two families inductively.
This is the indexing set for the function, and `invVal` is the function part. -/
inductive InvTy (l r : Type u) : Bool → Type u
  | zero : InvTy l r false
  | left₁ : r → InvTy l r false → InvTy l r false
  | left₂ : l → InvTy l r true → InvTy l r false
  | right₁ : l → InvTy l r false → InvTy l r true
  | right₂ : r → InvTy l r true → InvTy l r true
goal: SetTheory.PGame.InvTy l r false

full_name: SetTheory.PGame.InvTy.left₁
code: /-- Because the two halves of the definition of `inv` produce more elements
on each side, we have to define the two families inductively.
This is the indexing set for the function, and `invVal` is the function part. -/
inductive InvTy (l r : Type u) : Bool → Type u
  | zero : InvTy l r false
  | left₁ : r → InvTy l r false → InvTy l r false
  | left₂ : l → InvTy l r true → InvTy l r false
  | right₁ : l → InvTy l r false → InvTy l r true
  | right₂ : r → InvTy l r true → InvTy l r true
goal: r → SetTheory.PGame.InvTy l r false → SetTheory.PGame.InvTy l r false

full_name: SetTheory.PGame.instIsEmptyInvTyTrue
code: instance (l r : Type u) [IsEmpty l] [IsEmpty r] : IsEmpty (InvTy l r true) 
goal: IsEmpty (SetTheory.PGame.InvTy l r true)

full_name: SetTheory.PGame.InvTy.instInhabited
code: instance InvTy.instInhabited (l r : Type u) : Inhabited (InvTy l r false) 
goal: Inhabited (SetTheory.PGame.InvTy l r false)

full_name: SetTheory.PGame.uniqueInvTy
code: instance uniqueInvTy (l r : Type u) [IsEmpty l] [IsEmpty r] : Unique (InvTy l r false) 
goal: Unique (SetTheory.PGame.InvTy l r false)

full_name: SetTheory.PGame.invVal
code: /-- Because the two halves of the definition of `inv` produce more elements
of each side, we have to define the two families inductively.
This is the function part, defined by recursion on `InvTy`. -/
def invVal {l r} (L : l → PGame) (R : r → PGame) (IHl : l → PGame) (IHr : r → PGame)
    (x : PGame) : ∀ {b}, InvTy l r b → PGame
  
goal: SetTheory.PGame.InvTy l r b → SetTheory.PGame

full_name: SetTheory.PGame.invVal_isEmpty
code: @[simp]
theorem invVal_isEmpty {l r : Type u} {b} (L R IHl IHr) (i : InvTy l r b) (x) [IsEmpty l]
    [IsEmpty r] : invVal L R IHl IHr x i = 0 
goal: SetTheory.PGame.invVal L R IHl IHr x i = 0

full_name: SetTheory.PGame.inv'
code: /-- The inverse of a positive surreal number `x = {L | R}` is
given by `x⁻¹ = {0,
  (1 + (R - x) * x⁻¹L) * R, (1 + (L - x) * x⁻¹R) * L |
  (1 + (L - x) * x⁻¹L) * L, (1 + (R - x) * x⁻¹R) * R}`.
Because the two halves `x⁻¹L, x⁻¹R` of `x⁻¹` are used in their own
definition, the sets and elements are inductively generated. -/
def inv' : PGame → PGame
  
goal: SetTheory.PGame → SetTheory.PGame

full_name: SetTheory.PGame.zero_lf_inv'
code: theorem zero_lf_inv' : ∀ x : PGame, 0 ⧏ inv' x
  
goal: SetTheory.PGame.LF 0 x.inv'

full_name: SetTheory.PGame.inv'Zero
code: /-- `inv' 0` has exactly the same moves as `1`. -/
def inv'Zero : inv' 0 ≡r 1 
goal: (SetTheory.PGame.inv' 0).Relabelling 1

full_name: SetTheory.PGame.inv'_zero_equiv
code: theorem inv'_zero_equiv : inv' 0 ≈ 1 
goal: SetTheory.PGame.inv' 0 ≈ 1

full_name: SetTheory.PGame.inv'One
code: /-- `inv' 1` has exactly the same moves as `1`. -/
def inv'One : inv' 1 ≡r (1 : PGame.{u}) 
goal: (SetTheory.PGame.inv' 1).Relabelling 1

full_name: SetTheory.PGame.inv'_one_equiv
code: theorem inv'_one_equiv : inv' 1 ≈ 1 
goal: SetTheory.PGame.inv' 1 ≈ 1

full_name: SetTheory.PGame.instInv
code: /-- The inverse of a pre-game in terms of the inverse on positive pre-games. -/
noncomputable instance : Inv PGame 
goal: Inv SetTheory.PGame

full_name: SetTheory.PGame.instDiv
code: noncomputable instance : Div PGame 
goal: Div SetTheory.PGame

full_name: SetTheory.PGame.inv_eq_of_equiv_zero
code: theorem inv_eq_of_equiv_zero {x : PGame} (h : x ≈ 0) : x⁻¹ = 0 
goal: x⁻¹ = 0

full_name: SetTheory.PGame.inv_zero
code: @[simp]
theorem inv_zero : (0 : PGame)⁻¹ = 0 
goal: 0⁻¹ = 0

full_name: SetTheory.PGame.inv_eq_of_pos
code: theorem inv_eq_of_pos {x : PGame} (h : 0 < x) : x⁻¹ = inv' x 
goal: x⁻¹ = x.inv'

full_name: SetTheory.PGame.inv_eq_of_lf_zero
code: theorem inv_eq_of_lf_zero {x : PGame} (h : x ⧏ 0) : x⁻¹ = -inv' (-x) 
goal: x⁻¹ = -(-x).inv'

full_name: SetTheory.PGame.invOne
code: /-- `1⁻¹` has exactly the same moves as `1`. -/
def invOne : 1⁻¹ ≡r 1 
goal: 1⁻¹.Relabelling 1

full_name: SetTheory.PGame.inv_one_equiv
code: theorem inv_one_equiv : (1⁻¹ : PGame) ≈ 1 
goal: 1⁻¹ ≈ 1