Documentation

CombinatorialGames.Game.IGame

Combinatorial (pre-)games #

The basic theory of combinatorial games, following Conway's book On Numbers and Games.

In ZFC, games are built inductively out of two other sets of games, representing the options for two players Left and Right. In Lean, we instead define the type of games IGame as arising from two Small sets of games, with notation {s | t}ᴵ (see IGame.ofSets). A u-small type α : Type v is one that is equivalent to some β : Type u, and the distinction between small and large types in a given universe closely mimics the ZFC distinction between sets and proper classes.

This definition requires some amount of setup, which we achieve through an auxiliary type PGame. This type was historically the foundation for game theory in Lean, but it has now been superseded by IGame, a quotient of it with the correct notion of equality. See the docstring on PGame for more information.

We are also interested in further quotients of IGame. The quotient of games under equivalence x ≈ y ↔ x ≤ y ∧ y ≤ x, which in the literature is often what is meant by a "combinatorial game", is defined as Game in CombinatorialGames.Game.Basic. The surreal numbers Surreal are defined as a quotient (of a subtype) of games in CombinatorialGames.Surreal.Basic.

Conway induction #

Most constructions within game theory, and as such, many proofs within it, are done by structural induction. Structural induction on games is sometimes called "Conway induction".

The most straightforward way to employ Conway induction is by using the termination checker, with the auxiliary igame_wf tactic. This uses solve_by_elim to search the context for proofs of the form y ∈ x.leftMoves or y ∈ x.rightMoves, which prove termination. Alternatively, you can use the explicit recursion principles IGame.ofSetsRecOn or IGame.moveRecOn.

Order properties #

Pregames have both a and a < relation, satisfying the properties of a Preorder. The relation 0 < x means that x can always be won by Left, while 0 ≤ x means that x can be won by Left as the second player. Likewise, x < 0 means that x can always be won by Right, while x ≤ 0 means that x can be won by Right as the second player.

Note that we don't actually prove these characterizations. Indeed, in Conway's setup, combinatorial game theory can be done entirely without the concept of a strategy. For instance, IGame.zero_le implies that if 0 ≤ x, then any move by Right satisfies ¬ x ≤ 0, and IGame.zero_lf implies that if ¬ x ≤ 0, then some move by Left satisfies 0 ≤ x. The strategy is thus already encoded within these game relations.

For convenience, we define notation x ⧏ y (pronounced "less or fuzzy") for ¬ y ≤ x, notation x ‖ y for ¬ x ≤ y ∧ ¬ y ≤ x, and notation x ≈ y for x ≤ y ∧ y ≤ x.

You can prove most (simple) inequalities on concrete games through the game_cmp tactic, which repeatedly unfolds the definition of and applies simp until it solves the goal.

Algebraic structures #

Most of the usual arithmetic operations can be defined for games. Addition is defined for x = {s₁ | t₁}ᴵ and y = {s₂ | t₂}ᴵ by x + y = {s₁ + y, x + s₂ | t₁ + y, x + t₂}ᴵ. Negation is defined by -{s | t}ᴵ = {-t | -s}ᴵ.

The order structures interact in the expected way with arithmetic. In particular, Game is an OrderedAddCommGroup. Meanwhile, IGame satisfies the slightly weaker axioms of a SubtractionCommMonoid, since the equation x - x = 0 is only true up to equivalence.

Pre-games #

inductive PGame :
Type (u + 1)

The type of "pre-games", before we have quotiented by equivalence (identicalSetoid).

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 pre-game is built inductively from two families of pre-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.

This type was historically the foundation for game theory in Lean, but this led to many annoyances. Most impactfully, this type has a notion of equality that is too strict: two games 0 = { | } could be distinct (and unprovably so!) if the indexed families of left and right sets were two distinct empty types. To get the correct notion of equality, we define IGame as the quotient of this type by the Identical relation, representing extensional equivalence.

This type has thus been relegated to an auxiliary construction for IGame. You should not build any substantial theory based on this type.

Instances For

    The indexing type for allowable moves by Left.

    Equations
    Instances For

      The indexing type for allowable moves by Right.

      Equations
      Instances For

        The new game after Left makes an allowed move.

        Equations
        Instances For

          The new game after Right makes an allowed move.

          Equations
          Instances For
            @[simp]
            theorem PGame.leftMoves_mk {xl xr : Type u_1} {xL : xlPGame} {xR : xrPGame} :
            (mk xl xr xL xR).LeftMoves = xl
            @[simp]
            theorem PGame.moveLeft_mk {xl xr : Type u_1} {xL : xlPGame} {xR : xrPGame} :
            (mk xl xr xL xR).moveLeft = xL
            @[simp]
            theorem PGame.rightMoves_mk {xl xr : Type u_1} {xL : xlPGame} {xR : xrPGame} :
            (mk xl xr xL xR).RightMoves = xr
            @[simp]
            theorem PGame.moveRight_mk {xl xr : Type u_1} {xL : xlPGame} {xR : xrPGame} :
            (mk xl xr xL xR).moveRight = xR

            Two pre-games are identical if their left and right sets are identical. That is, Identical x y if every left move of x is identical to some left move of y, every right move of x is identical to some right move of y, and vice versa.

            IGame is defined as a quotient of PGame under this relation.

            Equations
            Instances For

              Two pre-games are identical if their left and right sets are identical. That is, Identical x y if every left move of x is identical to some left move of y, every right move of x is identical to some right move of y, and vice versa.

              IGame is defined as a quotient of PGame under this relation.

              Equations
              Instances For
                theorem PGame.identical_iff {x y : PGame} :
                x.Identical y (Relator.BiTotal fun (x1 : x.LeftMoves) (x2 : y.LeftMoves) => (x.moveLeft x1).Identical (y.moveLeft x2)) Relator.BiTotal fun (x1 : x.RightMoves) (x2 : y.RightMoves) => (x.moveRight x1).Identical (y.moveRight x2)
                theorem PGame.Identical.trans {x y z : PGame} :
                x.Identical yy.Identical zx.Identical z
                theorem PGame.Identical.moveLeft {x y : PGame} :
                x.Identical y∀ (i : x.LeftMoves), ∃ (j : y.LeftMoves), (x.moveLeft i).Identical (y.moveLeft j)

                If x ≡ y, then a left move of x is identical to some left move of y.

                theorem PGame.Identical.moveLeft_symm {x y : PGame} :
                x.Identical y∀ (i : y.LeftMoves), ∃ (j : x.LeftMoves), (x.moveLeft j).Identical (y.moveLeft i)

                If x ≡ y, then a left move of y is identical to some left move of x.

                theorem PGame.Identical.moveRight {x y : PGame} :
                x.Identical y∀ (i : x.RightMoves), ∃ (j : y.RightMoves), (x.moveRight i).Identical (y.moveRight j)

                If x ≡ y, then a right move of x is identical to some right move of y.

                theorem PGame.Identical.moveRight_symm {x y : PGame} :
                x.Identical y∀ (i : y.RightMoves), ∃ (j : x.RightMoves), (x.moveRight j).Identical (y.moveRight i)

                If x ≡ y, then a right move of y is identical to some right move of x.

                Game moves #

                def IGame :
                Type (u + 1)

                Games up to identity.

                IGame uses the set-theoretic notion of equality on games, compared to PGame's 'type-theoretic' notion of equality.

                This is not the same equivalence as used broadly in combinatorial game theory literature, as a game like {0, 1 | 0} is not identical to {1 | 0}, despite being equivalent. However, many theorems can be proven over the 'identical' equivalence relation, and the literature may occasionally specifically use the 'identical' equivalence relation for this reason.

                For the more common game equivalence from literature, see Game.Basic.

                Equations
                Instances For
                  def IGame.mk (x : PGame) :

                  The quotient map from PGame into IGame.

                  Equations
                  Instances For
                    theorem IGame.mk_eq_mk {x y : PGame} :
                    mk x = mk y x.Identical y
                    theorem IGame.mk_eq {x y : PGame} :
                    x.Identical ymk x = mk y

                    Alias of the reverse direction of IGame.mk_eq_mk.

                    Alias of the reverse direction of IGame.mk_eq_mk.


                    Alias of the reverse direction of IGame.mk_eq_mk.

                    theorem IGame.ind {P : IGameProp} (H : ∀ (y : PGame), P (mk y)) (x : IGame) :
                    P x
                    def IGame.out (x : IGame) :

                    Choose an element of the equivalence class using the axiom of choice.

                    Equations
                    Instances For
                      @[simp]
                      theorem IGame.out_eq (x : IGame) :
                      mk x.out = x

                      The set of left moves of the game.

                      Equations
                      Instances For

                        The set of right moves of the game.

                        Equations
                        Instances For
                          theorem IGame.ext {x y : IGame} (hl : x.leftMoves = y.leftMoves) (hr : x.rightMoves = y.rightMoves) :
                          x = y

                          IsOption x y means that x is either a left or a right move for y.

                          Equations
                          Instances For
                            def IGame.moveRecOn {P : IGameSort u_1} (x : IGame) (H : (x : IGame) → ((y : IGame) → y x.leftMovesP y)((y : IGame) → y x.rightMovesP y)P x) :
                            P x

                            Conway recursion: build data for a game by recursively building it on its left and right sets.

                            See ofSetsRecOn for an alternate form.

                            Equations
                            • One or more equations did not get rendered due to their size.
                            Instances For
                              theorem IGame.moveRecOn_eq {P : IGameSort u_1} (x : IGame) (H : (x : IGame) → ((y : IGame) → y x.leftMovesP y)((y : IGame) → y x.rightMovesP y)P x) :
                              x.moveRecOn H = H x (fun (y : IGame) (x : y x.leftMoves) => y.moveRecOn H) fun (y : IGame) (x : y x.rightMoves) => y.moveRecOn H

                              A (proper) subposition is any game in the transitive closure of IsOption.

                              Equations
                              Instances For
                                theorem IGame.Subposition.trans {x y z : IGame} (h₁ : x.Subposition y) (h₂ : y.Subposition z) :

                                Discharges proof obligations of the form Subposition .. arising in termination proofs of definitions using well-founded recursion on IGame.

                                Equations
                                Instances For

                                  Construct an IGame from its left and right sets.

                                  This is given notation {s | t}ᴵ, where the superscript I is to disambiguate from set builder notation, and from the analogous constructors on Game and Surreal.

                                  This function is regrettably noncomputable. Among other issues, sets simply do not carry data in Lean. To perform computations on IGame we can instead make use of the game_cmp tactic.

                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For

                                    Construct an IGame from its left and right sets.

                                    This is given notation {s | t}ᴵ, where the superscript I is to disambiguate from set builder notation, and from the analogous constructors on Game and Surreal.

                                    This function is regrettably noncomputable. Among other issues, sets simply do not carry data in Lean. To perform computations on IGame we can instead make use of the game_cmp tactic.

                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    Instances For
                                      @[simp]
                                      theorem IGame.ofSets_inj {s₁ s₂ t₁ t₂ : Set IGame} [Small.{u_1, u_1 + 1} s₁] [Small.{u_1, u_1 + 1} s₂] [Small.{u_1, u_1 + 1} t₁] [Small.{u_1, u_1 + 1} t₂] :
                                      {s₁ | t₁}ᴵ = {s₂ | t₂}ᴵ s₁ = s₂ t₁ = t₂
                                      def IGame.ofSetsRecOn {P : IGameSort u_1} (x : IGame) (H : (s t : Set IGame) → [inst : Small.{u, u + 1} s] → [inst_1 : Small.{u, u + 1} t] → ((x : IGame) → x sP x)((x : IGame) → x tP x)P {s | t}ᴵ) :
                                      P x

                                      Conway recursion: build data for a game by recursively building it on its left and right sets.

                                      See moveRecOn for an alternate form.

                                      Equations
                                      • One or more equations did not get rendered due to their size.
                                      Instances For
                                        @[simp]
                                        theorem IGame.ofSetsRecOn_ofSets {P : IGameSort u_1} (s t : Set IGame) [Small.{u, u + 1} s] [Small.{u, u + 1} t] (H : (s t : Set IGame) → [inst : Small.{u, u + 1} s] → [inst_1 : Small.{u, u + 1} t] → ((x : IGame) → x sP x)((x : IGame) → x tP x)P {s | t}ᴵ) :
                                        {s | t}ᴵ.ofSetsRecOn H = H s t (fun (y : IGame) (x : y s) => y.ofSetsRecOn H) fun (y : IGame) (x : y t) => y.ofSetsRecOn H

                                        Basic games #

                                        The game 0 = {∅ | ∅}ᴵ.

                                        Equations

                                        The game 1 = {{0} | ∅}ᴵ.

                                        Equations

                                        Order relations #

                                        The less or equal relation on games.

                                        If 0 ≤ x, then Left can win x as the second player. x ≤ y means that 0 ≤ y - x.

                                        Equations
                                        • One or more equations did not get rendered due to their size.

                                        The less or fuzzy relation on pre-games. x ⧏ y is notation for ¬ y ≤ x.

                                        If 0 ⧏ x, then Left can win x as the first player. x ⧏ y means that 0 ⧏ y - x.

                                        Equations
                                        Instances For
                                          theorem IGame.le_iff_forall_lf {x y : IGame} :
                                          x y (∀ zx.leftMoves, ¬y z) zy.rightMoves, ¬z x

                                          Definition of x ≤ y on pre-games, in terms of .

                                          theorem IGame.lf_iff_exists_le {x y : IGame} :
                                          ¬y x (∃ zy.leftMoves, x z) zx.rightMoves, z y

                                          Definition of x ⧏ y on pre-games, in terms of .

                                          theorem IGame.zero_le {x : IGame} :
                                          0 x yx.rightMoves, ¬y 0

                                          The definition of 0 ≤ x on pre-games, in terms of 0 ⧏.

                                          theorem IGame.le_zero {x : IGame} :
                                          x 0 yx.leftMoves, ¬0 y

                                          The definition of x ≤ 0 on pre-games, in terms of ⧏ 0.

                                          theorem IGame.zero_lf {x : IGame} :
                                          ¬x 0 yx.leftMoves, 0 y

                                          The definition of 0 ⧏ x on pre-games, in terms of 0 ≤.

                                          theorem IGame.lf_zero {x : IGame} :
                                          ¬0 x yx.rightMoves, y 0

                                          The definition of x ⧏ 0 on pre-games, in terms of ≤ 0.

                                          theorem IGame.le_def {x y : IGame} :
                                          x y (∀ ax.leftMoves, (∃ by.leftMoves, a b) ba.rightMoves, b y) ay.rightMoves, (∃ ba.leftMoves, x b) bx.rightMoves, b a

                                          The definition of x ≤ y on pre-games, in terms of two moves later.

                                          Note that it's often more convenient to use le_iff_forall_lf, which only unfolds the definition by one step.

                                          theorem IGame.lf_def {x y : IGame} :
                                          ¬y x (∃ ay.leftMoves, (∀ bx.leftMoves, ¬a b) ba.rightMoves, ¬b x) ax.rightMoves, (∀ ba.leftMoves, ¬y b) by.rightMoves, ¬b a

                                          The definition of x ⧏ y on pre-games, in terms of two moves later.

                                          Note that it's often more convenient to use lf_iff_exists_le, which only unfolds the definition by one step.

                                          theorem IGame.leftMove_lf_of_le {x y z : IGame} (h : x y) (h' : z x.leftMoves) :
                                          ¬y z
                                          theorem IGame.lf_rightMove_of_le {x y z : IGame} (h : x y) (h' : z y.rightMoves) :
                                          ¬z x
                                          theorem IGame.lf_of_le_leftMove {x y z : IGame} (h : x z) (h' : z y.leftMoves) :
                                          ¬y x
                                          theorem IGame.lf_of_rightMove_le {x y z : IGame} (h : z y) (h' : z x.rightMoves) :
                                          ¬y x
                                          Equations
                                          theorem IGame.leftMove_lf {x y : IGame} (h : y x.leftMoves) :
                                          ¬x y
                                          theorem IGame.lf_rightMove {x y : IGame} (h : y x.rightMoves) :
                                          ¬y x

                                          The equivalence relation x ≈ y means that x ≤ y and y ≤ x. This is notation for AntisymmRel (⬝ ≤ ⬝) x y.

                                          Equations
                                          Instances For

                                            The "fuzzy" relation x ‖ y means that x ⧏ y and y ⧏ x. This is notation for IncompRel (⬝ ≤ ⬝) x y.

                                            Equations
                                            Instances For
                                              Equations
                                              • One or more equations did not get rendered due to their size.
                                              Instances For
                                                Equations
                                                • One or more equations did not get rendered due to their size.
                                                Instances For
                                                  theorem IGame.equiv_of_exists {x y : IGame} (hl₁ : ax.leftMoves, by.leftMoves, ab) (hr₁ : ax.rightMoves, by.rightMoves, ab) (hl₂ : by.leftMoves, ax.leftMoves, ab) (hr₂ : by.rightMoves, ax.rightMoves, ab) :
                                                  xy
                                                  @[simp]
                                                  theorem IGame.zero_lt_one :
                                                  0 < 1

                                                  Negation #

                                                  instance IGame.instSmallElemNegSet {α : Type u_1} [InvolutiveNeg α] (s : Set α) [Small.{u, u_1} s] :

                                                  The negative of a game is defined by -{s | t}ᴵ = {-t | -s}ᴵ.

                                                  Equations
                                                  @[simp]
                                                  theorem IGame.isOption_neg_neg {x y : IGame} :
                                                  (-x).IsOption (-y) x.IsOption y
                                                  theorem IGame.forall_leftMoves_neg {P : IGameProp} {x : IGame} :
                                                  (∀ y(-x).leftMoves, P y) yx.rightMoves, P (-y)
                                                  theorem IGame.forall_rightMoves_neg {P : IGameProp} {x : IGame} :
                                                  (∀ y(-x).rightMoves, P y) yx.leftMoves, P (-y)
                                                  theorem IGame.exists_leftMoves_neg {P : IGameProp} {x : IGame} :
                                                  (∃ y(-x).leftMoves, P y) yx.rightMoves, P (-y)
                                                  theorem IGame.exists_rightMoves_neg {P : IGameProp} {x : IGame} :
                                                  (∃ y(-x).rightMoves, P y) yx.leftMoves, P (-y)
                                                  @[simp]
                                                  theorem IGame.neg_le_neg_iff {x y : IGame} :
                                                  -x -y y x
                                                  theorem IGame.neg_le {x y : IGame} :
                                                  -x y -y x
                                                  theorem IGame.le_neg {x y : IGame} :
                                                  x -y y -x
                                                  @[simp]
                                                  theorem IGame.neg_lt_neg_iff {x y : IGame} :
                                                  -x < -y y < x
                                                  theorem IGame.neg_lt {x y : IGame} :
                                                  -x < y -y < x
                                                  theorem IGame.lt_neg {x y : IGame} :
                                                  x < -y y < -x
                                                  @[simp]
                                                  theorem IGame.neg_equiv_neg_iff {x y : IGame} :
                                                  -x-y xy
                                                  theorem IGame.neg_congr {x y : IGame} :
                                                  xy-x-y

                                                  Alias of the reverse direction of IGame.neg_equiv_neg_iff.

                                                  @[simp]
                                                  theorem IGame.neg_fuzzy_neg_iff {x y : IGame} :
                                                  -x-y xy
                                                  @[simp]
                                                  theorem IGame.neg_le_zero {x : IGame} :
                                                  -x 0 0 x
                                                  @[simp]
                                                  theorem IGame.zero_le_neg {x : IGame} :
                                                  0 -x x 0
                                                  @[simp]
                                                  theorem IGame.neg_lt_zero {x : IGame} :
                                                  -x < 0 0 < x
                                                  @[simp]
                                                  theorem IGame.zero_lt_neg {x : IGame} :
                                                  0 < -x x < 0
                                                  @[simp]
                                                  theorem IGame.neg_equiv_zero {x : IGame} :
                                                  -x0 x0
                                                  @[simp]
                                                  theorem IGame.zero_equiv_neg {x : IGame} :
                                                  0-x 0x
                                                  @[simp]
                                                  theorem IGame.neg_fuzzy_zero {x : IGame} :
                                                  -x0 x0
                                                  @[simp]
                                                  theorem IGame.zero_fuzzy_neg {x : IGame} :
                                                  0-x 0x

                                                  Addition and subtraction #

                                                  The sum of x = {s₁ | t₁}ᴵ and y = {s₂ | t₂}ᴵ is {s₁ + y, x + s₂ | t₁ + y, x + t₂}ᴵ.

                                                  Equations
                                                  theorem IGame.add_eq (x y : IGame) :
                                                  x + y = {(fun (x : IGame) => x + y) '' x.leftMoves (fun (x_1 : IGame) => x + x_1) '' y.leftMoves | (fun (x : IGame) => x + y) '' x.rightMoves (fun (x_1 : IGame) => x + x_1) '' y.rightMoves}ᴵ
                                                  theorem IGame.ofSets_add_ofSets (s₁ t₁ s₂ t₂ : Set IGame) [Small.{u_1, u_1 + 1} s₁] [Small.{u_1, u_1 + 1} t₁] [Small.{u_1, u_1 + 1} s₂] [Small.{u_1, u_1 + 1} t₂] :
                                                  {s₁ | t₁}ᴵ + {s₂ | t₂}ᴵ = {(fun (x : IGame) => x + {s₂ | t₂}ᴵ) '' s₁ (fun (x : IGame) => {s₁ | t₁}ᴵ + x) '' s₂ | (fun (x : IGame) => x + {s₂ | t₂}ᴵ) '' t₁ (fun (x : IGame) => {s₁ | t₁}ᴵ + x) '' t₂}ᴵ
                                                  @[simp]
                                                  theorem IGame.leftMoves_add (x y : IGame) :
                                                  (x + y).leftMoves = (fun (x : IGame) => x + y) '' x.leftMoves (fun (x_1 : IGame) => x + x_1) '' y.leftMoves
                                                  @[simp]
                                                  theorem IGame.rightMoves_add (x y : IGame) :
                                                  (x + y).rightMoves = (fun (x : IGame) => x + y) '' x.rightMoves (fun (x_1 : IGame) => x + x_1) '' y.rightMoves
                                                  theorem IGame.add_left_mem_leftMoves_add {x y : IGame} (h : x y.leftMoves) (z : IGame) :
                                                  z + x (z + y).leftMoves
                                                  theorem IGame.add_right_mem_leftMoves_add {x y : IGame} (h : x y.leftMoves) (z : IGame) :
                                                  x + z (y + z).leftMoves
                                                  theorem IGame.IsOption.add_left {x y z : IGame} (h : x.IsOption y) :
                                                  (z + x).IsOption (z + y)
                                                  theorem IGame.IsOption.add_right {x y z : IGame} (h : x.IsOption y) :
                                                  (x + z).IsOption (y + z)
                                                  theorem IGame.forall_leftMoves_add {P : IGameProp} {x y : IGame} :
                                                  (∀ a(x + y).leftMoves, P a) (∀ ax.leftMoves, P (a + y)) by.leftMoves, P (x + b)
                                                  theorem IGame.forall_rightMoves_add {P : IGameProp} {x y : IGame} :
                                                  (∀ a(x + y).rightMoves, P a) (∀ ax.rightMoves, P (a + y)) by.rightMoves, P (x + b)
                                                  theorem IGame.exists_leftMoves_add {P : IGameProp} {x y : IGame} :
                                                  (∃ a(x + y).leftMoves, P a) (∃ ax.leftMoves, P (a + y)) by.leftMoves, P (x + b)
                                                  theorem IGame.exists_rightMoves_add {P : IGameProp} {x y : IGame} :
                                                  (∃ a(x + y).rightMoves, P a) (∃ ax.rightMoves, P (a + y)) by.rightMoves, P (x + b)
                                                  @[simp]
                                                  theorem IGame.add_eq_zero_iff {x y : IGame} :
                                                  x + y = 0 x = 0 y = 0
                                                  Equations
                                                  • One or more equations did not get rendered due to their size.

                                                  The subtraction of x and y is defined as x + (-y).

                                                  Equations
                                                  • One or more equations did not get rendered due to their size.
                                                  @[simp]
                                                  theorem IGame.leftMoves_sub (x y : IGame) :
                                                  (x - y).leftMoves = (fun (x : IGame) => x - y) '' x.leftMoves (fun (x_1 : IGame) => x + x_1) '' (-y.rightMoves)
                                                  @[simp]
                                                  theorem IGame.rightMoves_sub (x y : IGame) :
                                                  (x - y).rightMoves = (fun (x : IGame) => x - y) '' x.rightMoves (fun (x_1 : IGame) => x + x_1) '' (-y.leftMoves)
                                                  theorem IGame.sub_left_mem_leftMoves_sub {x y : IGame} (h : x y.rightMoves) (z : IGame) :
                                                  z - x (z - y).leftMoves
                                                  theorem IGame.sub_right_mem_leftMoves_sub {x y : IGame} (h : x y.leftMoves) (z : IGame) :
                                                  x - z (y - z).leftMoves
                                                  theorem IGame.sub_left_mem_rightMoves_sub {x y : IGame} (h : x y.leftMoves) (z : IGame) :
                                                  z - x (z - y).rightMoves
                                                  Equations
                                                  • One or more equations did not get rendered due to their size.
                                                  theorem IGame.sub_self_equiv (x : IGame) :
                                                  x - x0

                                                  The sum of a game and its negative is equivalent, though not necessarily identical to zero.

                                                  theorem IGame.neg_add_equiv (x : IGame) :
                                                  -x + x0

                                                  The sum of a game and its negative is equivalent, though not necessarily identical to zero.

                                                  @[simp]
                                                  theorem IGame.add_fuzzy_add_iff_left {a b c : IGame} :
                                                  a + ba + c bc
                                                  @[simp]
                                                  theorem IGame.add_fuzzy_add_iff_right {a b c : IGame} :
                                                  b + ac + a bc

                                                  We define the NatCast instance as ↑0 = 0 and ↑(n + 1) = {{↑n} | ∅}ᴵ.

                                                  Note that this is equivalent, but not identical, to the more common definition ↑n = {Iio n | ∅}ᴵ. For that, use Ordinal.toIGame.

                                                  Equations
                                                  • One or more equations did not get rendered due to their size.

                                                  This version of the theorem is more convenient for the game_cmp tactic.

                                                  @[simp]
                                                  theorem IGame.leftMoves_natCast_succ (n : ) :
                                                  (n + 1).leftMoves = {n}
                                                  @[simp]
                                                  @[simp]
                                                  theorem IGame.natCast_succ_eq (n : ) :
                                                  n + 1 = {{n} | }ᴵ
                                                  theorem IGame.eq_natCast_of_mem_leftMoves_natCast {n : } {x : IGame} (hx : x (↑n).leftMoves) :
                                                  m < n, m = x

                                                  Every left option of a natural number is equal to a smaller natural number.

                                                  Equations
                                                  @[simp]
                                                  theorem IGame.intCast_nat (n : ) :
                                                  n = n
                                                  @[simp]
                                                  theorem IGame.intCast_ofNat (n : ) :
                                                  (OfNat.ofNat n) = n
                                                  @[simp]
                                                  theorem IGame.intCast_negSucc (n : ) :
                                                  (Int.negSucc n) = -(n + 1)
                                                  theorem IGame.intCast_zero :
                                                  0 = 0
                                                  theorem IGame.intCast_one :
                                                  1 = 1
                                                  @[simp]
                                                  theorem IGame.intCast_neg (n : ) :
                                                  ↑(-n) = -n
                                                  theorem IGame.eq_sub_one_of_mem_leftMoves_intCast {n : } {x : IGame} (hx : x (↑n).leftMoves) :
                                                  x = ↑(n - 1)
                                                  theorem IGame.eq_add_one_of_mem_rightMoves_intCast {n : } {x : IGame} (hx : x (↑n).rightMoves) :
                                                  x = ↑(n + 1)
                                                  theorem IGame.eq_intCast_of_mem_leftMoves_intCast {n : } {x : IGame} (hx : x (↑n).leftMoves) :
                                                  m < n, m = x

                                                  Every left option of an integer is equal to a smaller integer.

                                                  theorem IGame.eq_intCast_of_mem_rightMoves_intCast {n : } {x : IGame} (hx : x (↑n).rightMoves) :
                                                  ∃ (m : ), n < m m = x

                                                  Every right option of an integer is equal to a larger integer.

                                                  Multiplication #

                                                  @[irreducible]
                                                  def IGame.mul' (x y : IGame) :
                                                  Equations
                                                  • One or more equations did not get rendered due to their size.
                                                  Instances For

                                                    The product of x = {s₁ | t₁}ᴵ and y = {s₂ | t₂}ᴵ is {a₁ * y + x * b₁ - a₁ * b₁ | a₂ * y + x * b₂ - a₂ * b₂}ᴵ, where (a₁, b₁) ∈ s₁ ×ˢ s₂ ∪ t₁ ×ˢ t₂ and (a₂, b₂) ∈ s₁ ×ˢ t₂ ∪ t₁ ×ˢ s₂.

                                                    Using IGame.mulOption, this can alternatively be written as x * y = {mulOption x y a₁ b₁ | mulOption x y a₂ b₂}ᴵ.

                                                    Equations
                                                    def IGame.mulOption (x y a b : IGame) :

                                                    The general option of x * y looks like a * y + x * b - a * b, for a and b options of x and y, respectively.

                                                    Equations
                                                    Instances For
                                                      theorem IGame.mul_eq (x y : IGame) :
                                                      x * y = {(fun (a : IGame × IGame) => mulOption x y a.1 a.2) '' (x.leftMoves ×ˢ y.leftMoves x.rightMoves ×ˢ y.rightMoves) | (fun (a : IGame × IGame) => mulOption x y a.1 a.2) '' (x.leftMoves ×ˢ y.rightMoves x.rightMoves ×ˢ y.leftMoves)}ᴵ
                                                      theorem IGame.ofSets_mul_ofSets (s₁ t₁ s₂ t₂ : Set IGame) [Small.{u_1, u_1 + 1} s₁] [Small.{u_1, u_1 + 1} t₁] [Small.{u_1, u_1 + 1} s₂] [Small.{u_1, u_1 + 1} t₂] :
                                                      {s₁ | t₁}ᴵ * {s₂ | t₂}ᴵ = {(fun (a : IGame × IGame) => mulOption {s₁ | t₁}ᴵ {s₂ | t₂}ᴵ a.1 a.2) '' (s₁ ×ˢ s₂ t₁ ×ˢ t₂) | (fun (a : IGame × IGame) => mulOption {s₁ | t₁}ᴵ {s₂ | t₂}ᴵ a.1 a.2) '' (s₁ ×ˢ t₂ t₁ ×ˢ s₂)}ᴵ
                                                      @[simp]
                                                      theorem IGame.leftMoves_mul (x y : IGame) :
                                                      (x * y).leftMoves = (fun (a : IGame × IGame) => mulOption x y a.1 a.2) '' (x.leftMoves ×ˢ y.leftMoves x.rightMoves ×ˢ y.rightMoves)
                                                      @[simp]
                                                      theorem IGame.rightMoves_mul (x y : IGame) :
                                                      (x * y).rightMoves = (fun (a : IGame × IGame) => mulOption x y a.1 a.2) '' (x.leftMoves ×ˢ y.rightMoves x.rightMoves ×ˢ y.leftMoves)
                                                      @[simp]
                                                      theorem IGame.leftMoves_mulOption (x y a b : IGame) :
                                                      (mulOption x y a b).leftMoves = (a * y + x * b - a * b).leftMoves
                                                      @[simp]
                                                      theorem IGame.rightMoves_mulOption (x y a b : IGame) :
                                                      (mulOption x y a b).rightMoves = (a * y + x * b - a * b).rightMoves
                                                      theorem IGame.mulOption_left_left_mem_leftMoves_mul {x y a b : IGame} (h₁ : a x.leftMoves) (h₂ : b y.leftMoves) :
                                                      mulOption x y a b (x * y).leftMoves
                                                      theorem IGame.mulOption_right_right_mem_leftMoves_mul {x y a b : IGame} (h₁ : a x.rightMoves) (h₂ : b y.rightMoves) :
                                                      mulOption x y a b (x * y).leftMoves
                                                      theorem IGame.mulOption_left_right_mem_rightMoves_mul {x y a b : IGame} (h₁ : a x.leftMoves) (h₂ : b y.rightMoves) :
                                                      mulOption x y a b (x * y).rightMoves
                                                      theorem IGame.mulOption_right_left_mem_rightMoves_mul {x y a b : IGame} (h₁ : a x.rightMoves) (h₂ : b y.leftMoves) :
                                                      mulOption x y a b (x * y).rightMoves
                                                      theorem IGame.IsOption.mul {x y a b : IGame} (h₁ : a.IsOption x) (h₂ : b.IsOption y) :
                                                      (mulOption x y a b).IsOption (x * y)
                                                      theorem IGame.forall_leftMoves_mul {P : IGameProp} {x y : IGame} :
                                                      (∀ a(x * y).leftMoves, P a) (∀ ax.leftMoves, by.leftMoves, P (mulOption x y a b)) ax.rightMoves, by.rightMoves, P (mulOption x y a b)
                                                      theorem IGame.forall_rightMoves_mul {P : IGameProp} {x y : IGame} :
                                                      (∀ a(x * y).rightMoves, P a) (∀ ax.leftMoves, by.rightMoves, P (mulOption x y a b)) ax.rightMoves, by.leftMoves, P (mulOption x y a b)
                                                      theorem IGame.exists_leftMoves_mul {P : IGameProp} {x y : IGame} :
                                                      (∃ a(x * y).leftMoves, P a) (∃ ax.leftMoves, by.leftMoves, P (mulOption x y a b)) ax.rightMoves, by.rightMoves, P (mulOption x y a b)
                                                      theorem IGame.exists_rightMoves_mul {P : IGameProp} {x y : IGame} :
                                                      (∃ a(x * y).rightMoves, P a) (∃ ax.leftMoves, by.rightMoves, P (mulOption x y a b)) ax.rightMoves, by.leftMoves, P (mulOption x y a b)
                                                      theorem IGame.mulOption_comm (x y a b : IGame) :
                                                      mulOption x y a b = mulOption y x b a
                                                      theorem IGame.mulOption_neg_left (x y a b : IGame) :
                                                      mulOption (-x) y a b = -mulOption x y (-a) b
                                                      theorem IGame.mulOption_neg_right (x y a b : IGame) :
                                                      mulOption x (-y) a b = -mulOption x y a (-b)
                                                      theorem IGame.mulOption_neg (x y a b : IGame) :
                                                      mulOption (-x) (-y) a b = mulOption x y (-a) (-b)

                                                      Distributivity and associativity only hold up to equivalence; we prove this in CombinatorialGames.Game.Basic.

                                                      Division #

                                                      The inverse of a positive game x = {s | t}ᴵ is {s' | t'}ᴵ, where s' and t' are the smallest sets such that 0 ∈ s', and such that (1 + (z - x) * a) / z, (1 + (y - x) * b) / y ∈ s' and (1 + (y - x) * a) / y, (1 + (z - x) * b) / z ∈ t' for y ∈ s positive, z ∈ t, a ∈ s', and b ∈ t'.

                                                      If x is negative, we define x⁻¹ = -(-x)⁻¹. For any other game, we set x⁻¹ = 0.

                                                      If x is a non-zero numeric game, then x * x⁻¹ ≈ 1. The value of this function on any non-numeric game should be treated as a junk value.

                                                      Equations
                                                      Equations
                                                      theorem IGame.div_eq_mul_inv (x y : IGame) :
                                                      x / y = x * y⁻¹
                                                      @[simp]
                                                      theorem IGame.inv_zero :
                                                      0⁻¹ = 0
                                                      @[simp]
                                                      theorem IGame.zero_div (x : IGame) :
                                                      0 / x = 0
                                                      @[simp]
                                                      theorem IGame.neg_div (x y : IGame) :
                                                      -x / y = -(x / y)
                                                      @[simp]
                                                      theorem IGame.inv_neg (x : IGame) :
                                                      def IGame.invOption (x y a : IGame) :

                                                      The general option of x⁻¹ looks like (1 + (y - x) * a) / y, for y an option of x, and a some other "earlier" option of x⁻¹.

                                                      Equations
                                                      Instances For
                                                        theorem IGame.inv_nonneg {x : IGame} (hx : 0 < x) :
                                                        theorem IGame.invOption_right_left_mem_leftMoves_inv {x y a : IGame} (hx : 0 < x) (hy : 0 < y) (hyx : y x.rightMoves) (ha : a x⁻¹.leftMoves) :
                                                        theorem IGame.invOption_left_right_mem_leftMoves_inv {x y a : IGame} (hx : 0 < x) (hy : 0 < y) (hyx : y x.leftMoves) (ha : a x⁻¹.rightMoves) :
                                                        theorem IGame.invOption_left_left_mem_rightMoves_inv {x y a : IGame} (hx : 0 < x) (hy : 0 < y) (hyx : y x.leftMoves) (ha : a x⁻¹.leftMoves) :
                                                        theorem IGame.invOption_right_right_mem_rightMoves_inv {x y a : IGame} (hx : 0 < x) (hy : 0 < y) (hyx : y x.rightMoves) (ha : a x⁻¹.rightMoves) :
                                                        theorem IGame.invRec {x : IGame} (hx : 0 < x) {P : (y : IGame) → y x⁻¹.leftMovesProp} {Q : (y : IGame) → y x⁻¹.rightMovesProp} (zero : P 0 ) (left₁ : ∀ (y : IGame) (hy : 0 < y) (hyx : y x.rightMoves) (a : IGame) (ha : a x⁻¹.leftMoves), P a haP (invOption x y a) ) (left₂ : ∀ (y : IGame) (hy : 0 < y) (hyx : y x.leftMoves) (a : IGame) (ha : a x⁻¹.rightMoves), Q a haP (invOption x y a) ) (right₁ : ∀ (y : IGame) (hy : 0 < y) (hyx : y x.leftMoves) (a : IGame) (ha : a x⁻¹.leftMoves), P a haQ (invOption x y a) ) (right₂ : ∀ (y : IGame) (hy : 0 < y) (hyx : y x.rightMoves) (a : IGame) (ha : a x⁻¹.rightMoves), Q a haQ (invOption x y a) ) :
                                                        (∀ (y : IGame) (hy : y x⁻¹.leftMoves), P y hy) ∀ (y : IGame) (hy : y x⁻¹.rightMoves), Q y hy

                                                        An induction principle on left and right moves of x⁻¹.

                                                        Equations
                                                        theorem IGame.ratCast_def (q : ) :
                                                        q = q.num / q.den
                                                        @[simp]
                                                        theorem IGame.ratCast_zero :
                                                        0 = 0
                                                        @[simp]
                                                        theorem IGame.ratCast_neg (q : ) :
                                                        ↑(-q) = -q