Documentation

Mathlib.SetTheory.Game.Basic

Combinatorial games. #

In this file we construct an instance OrderedAddCommGroup SetTheory.Game.

Multiplication on pre-games #

We define the operations of multiplication and inverse on pre-games, and prove a few basic theorems about them. Multiplication is not well-behaved under equivalence of pre-games i.e. x ≈ y does not imply x * z ≈ y * z. Hence, multiplication is not a well-defined operation on games. Nevertheless, the abelian group structure on games allows us to simplify many proofs for pre-games.

@[reducible, inline]
abbrev SetTheory.Game :
Type (u_1 + 1)

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.

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

    The less or fuzzy relation on games.

    If 0 ⧏ x (less or fuzzy with), then Left can win x as the first player.

    Equations
    Instances For
      @[simp]

      On Game, simp-normal inequalities should use as few negations as possible.

      @[simp]

      On Game, simp-normal inequalities should use as few negations as possible.

      It can be useful to use these lemmas to turn PGame inequalities into Game inequalities, as the AddCommGroup structure on Game often simplifies many proofs.

      The fuzzy, confused, or incomparable relation on games.

      If x ‖ 0, then the first player can always win x.

      Equations
      Instances For
        theorem SetTheory.Game.add_lf_add_right {b : SetTheory.Game} {c : SetTheory.Game} :
        b.LF c∀ (a : SetTheory.Game), (b + a).LF (c + a)
        theorem SetTheory.Game.add_lf_add_left {b : SetTheory.Game} {c : SetTheory.Game} :
        b.LF c∀ (a : SetTheory.Game), (a + b).LF (a + c)
        Equations
        • One or more equations did not get rendered due to their size.

        A small family of games is bounded above.

        A small set of games is bounded above.

        A small family of games is bounded below.

        A small set of games is bounded below.

        @[simp]
        theorem SetTheory.PGame.quot_neg (a : SetTheory.PGame) :
        -a = -a
        @[simp]
        theorem SetTheory.PGame.quot_add (a : SetTheory.PGame) (b : SetTheory.PGame) :
        a + b = a + b
        @[simp]
        theorem SetTheory.PGame.quot_sub (a : SetTheory.PGame) (b : SetTheory.PGame) :
        a - b = a - b
        theorem SetTheory.PGame.quot_eq_of_mk'_quot_eq {x : SetTheory.PGame} {y : SetTheory.PGame} (L : x.LeftMoves y.LeftMoves) (R : x.RightMoves y.RightMoves) (hl : ∀ (i : x.LeftMoves), x.moveLeft i = y.moveLeft (L i)) (hr : ∀ (j : x.RightMoves), x.moveRight j = y.moveRight (R j)) :
        x = y

        Multiplicative operations can be defined at the level of pre-games, but to prove their properties we need to use the abelian group structure of games. Hence we define them here.

        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 }.

        Equations
        • One or more equations did not get rendered due to their size.
        theorem SetTheory.PGame.leftMoves_mul (x : SetTheory.PGame) (y : SetTheory.PGame) :
        (x * y).LeftMoves = (x.LeftMoves × y.LeftMoves x.RightMoves × y.RightMoves)
        theorem SetTheory.PGame.rightMoves_mul (x : SetTheory.PGame) (y : SetTheory.PGame) :
        (x * y).RightMoves = (x.LeftMoves × y.RightMoves x.RightMoves × y.LeftMoves)
        def SetTheory.PGame.toLeftMovesMul {x : SetTheory.PGame} {y : SetTheory.PGame} :
        x.LeftMoves × y.LeftMoves x.RightMoves × y.RightMoves (x * y).LeftMoves

        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.

        Equations
        Instances For
          def SetTheory.PGame.toRightMovesMul {x : SetTheory.PGame} {y : SetTheory.PGame} :
          x.LeftMoves × y.RightMoves x.RightMoves × y.LeftMoves (x * y).RightMoves

          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.

          Equations
          Instances For
            @[simp]
            theorem SetTheory.PGame.mk_mul_moveLeft_inl {xl : Type u_1} {xr : Type u_1} {yl : Type u_1} {yr : Type u_1} {xL : xlSetTheory.PGame} {xR : xrSetTheory.PGame} {yL : ylSetTheory.PGame} {yR : yrSetTheory.PGame} {i : xl} {j : yl} :
            (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
            @[simp]
            theorem SetTheory.PGame.mul_moveLeft_inl {x : SetTheory.PGame} {y : SetTheory.PGame} {i : x.LeftMoves} {j : y.LeftMoves} :
            (x * y).moveLeft (SetTheory.PGame.toLeftMovesMul (Sum.inl (i, j))) = x.moveLeft i * y + x * y.moveLeft j - x.moveLeft i * y.moveLeft j
            @[simp]
            theorem SetTheory.PGame.mk_mul_moveLeft_inr {xl : Type u_1} {xr : Type u_1} {yl : Type u_1} {yr : Type u_1} {xL : xlSetTheory.PGame} {xR : xrSetTheory.PGame} {yL : ylSetTheory.PGame} {yR : yrSetTheory.PGame} {i : xr} {j : yr} :
            (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
            @[simp]
            theorem SetTheory.PGame.mul_moveLeft_inr {x : SetTheory.PGame} {y : SetTheory.PGame} {i : x.RightMoves} {j : y.RightMoves} :
            (x * y).moveLeft (SetTheory.PGame.toLeftMovesMul (Sum.inr (i, j))) = x.moveRight i * y + x * y.moveRight j - x.moveRight i * y.moveRight j
            @[simp]
            theorem SetTheory.PGame.mk_mul_moveRight_inl {xl : Type u_1} {xr : Type u_1} {yl : Type u_1} {yr : Type u_1} {xL : xlSetTheory.PGame} {xR : xrSetTheory.PGame} {yL : ylSetTheory.PGame} {yR : yrSetTheory.PGame} {i : xl} {j : yr} :
            (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
            @[simp]
            theorem SetTheory.PGame.mul_moveRight_inl {x : SetTheory.PGame} {y : SetTheory.PGame} {i : x.LeftMoves} {j : y.RightMoves} :
            (x * y).moveRight (SetTheory.PGame.toRightMovesMul (Sum.inl (i, j))) = x.moveLeft i * y + x * y.moveRight j - x.moveLeft i * y.moveRight j
            @[simp]
            theorem SetTheory.PGame.mk_mul_moveRight_inr {xl : Type u_1} {xr : Type u_1} {yl : Type u_1} {yr : Type u_1} {xL : xlSetTheory.PGame} {xR : xrSetTheory.PGame} {yL : ylSetTheory.PGame} {yR : yrSetTheory.PGame} {i : xr} {j : yl} :
            (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
            @[simp]
            theorem SetTheory.PGame.mul_moveRight_inr {x : SetTheory.PGame} {y : SetTheory.PGame} {i : x.RightMoves} {j : y.LeftMoves} :
            (x * y).moveRight (SetTheory.PGame.toRightMovesMul (Sum.inr (i, j))) = x.moveRight i * y + x * y.moveLeft j - x.moveRight i * y.moveLeft j
            theorem SetTheory.PGame.neg_mk_mul_moveLeft_inl {xl : Type u_1} {xr : Type u_1} {yl : Type u_1} {yr : Type u_1} {xL : xlSetTheory.PGame} {xR : xrSetTheory.PGame} {yL : ylSetTheory.PGame} {yR : yrSetTheory.PGame} {i : xl} {j : yr} :
            (-(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)
            theorem SetTheory.PGame.neg_mk_mul_moveLeft_inr {xl : Type u_1} {xr : Type u_1} {yl : Type u_1} {yr : Type u_1} {xL : xlSetTheory.PGame} {xR : xrSetTheory.PGame} {yL : ylSetTheory.PGame} {yR : yrSetTheory.PGame} {i : xr} {j : yl} :
            (-(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)
            theorem SetTheory.PGame.neg_mk_mul_moveRight_inl {xl : Type u_1} {xr : Type u_1} {yl : Type u_1} {yr : Type u_1} {xL : xlSetTheory.PGame} {xR : xrSetTheory.PGame} {yL : ylSetTheory.PGame} {yR : yrSetTheory.PGame} {i : xl} {j : yl} :
            (-(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)
            theorem SetTheory.PGame.neg_mk_mul_moveRight_inr {xl : Type u_1} {xr : Type u_1} {yl : Type u_1} {yr : Type u_1} {xL : xlSetTheory.PGame} {xR : xrSetTheory.PGame} {yL : ylSetTheory.PGame} {yR : yrSetTheory.PGame} {i : xr} {j : yr} :
            (-(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)
            theorem SetTheory.PGame.leftMoves_mul_cases {x : SetTheory.PGame} {y : SetTheory.PGame} (k : (x * y).LeftMoves) {P : (x * y).LeftMovesProp} (hl : ∀ (ix : x.LeftMoves) (iy : y.LeftMoves), P (SetTheory.PGame.toLeftMovesMul (Sum.inl (ix, iy)))) (hr : ∀ (jx : x.RightMoves) (jy : y.RightMoves), P (SetTheory.PGame.toLeftMovesMul (Sum.inr (jx, jy)))) :
            P k
            theorem SetTheory.PGame.rightMoves_mul_cases {x : SetTheory.PGame} {y : SetTheory.PGame} (k : (x * y).RightMoves) {P : (x * y).RightMovesProp} (hl : ∀ (ix : x.LeftMoves) (jy : y.RightMoves), P (SetTheory.PGame.toRightMovesMul (Sum.inl (ix, jy)))) (hr : ∀ (jx : x.RightMoves) (iy : y.LeftMoves), P (SetTheory.PGame.toRightMovesMul (Sum.inr (jx, iy)))) :
            P k
            @[irreducible]
            def SetTheory.PGame.mulCommRelabelling (x : SetTheory.PGame) (y : SetTheory.PGame) :
            (x * y).Relabelling (y * x)

            x * y and y * x have the same moves.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              theorem SetTheory.PGame.quot_mul_comm (x : SetTheory.PGame) (y : SetTheory.PGame) :
              x * y = y * x

              x * y is equivalent to y * x.

              Equations
              • =
              Equations
              • =
              Equations
              • =
              Equations
              • =

              x * 0 has exactly the same moves as 0.

              Equations
              Instances For

                x * 0 is equivalent to 0.

                @[simp]
                theorem SetTheory.PGame.quot_mul_zero (x : SetTheory.PGame) :
                x * 0 = 0

                0 * x has exactly the same moves as 0.

                Equations
                Instances For

                  0 * x is equivalent to 0.

                  @[simp]
                  theorem SetTheory.PGame.quot_zero_mul (x : SetTheory.PGame) :
                  0 * x = 0
                  @[irreducible]
                  def SetTheory.PGame.negMulRelabelling (x : SetTheory.PGame) (y : SetTheory.PGame) :
                  (-x * y).Relabelling (-(x * y))

                  -x * y and -(x * y) have the same moves.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    @[simp]
                    theorem SetTheory.PGame.quot_neg_mul (x : SetTheory.PGame) (y : SetTheory.PGame) :
                    -x * y = -x * y
                    def SetTheory.PGame.mulNegRelabelling (x : SetTheory.PGame) (y : SetTheory.PGame) :
                    (x * -y).Relabelling (-(x * y))

                    x * -y and -(x * y) have the same moves.

                    Equations
                    • x.mulNegRelabelling y = (x.mulCommRelabelling (-y)).trans ((y.negMulRelabelling x).trans (y.mulCommRelabelling x).negCongr)
                    Instances For
                      @[simp]
                      theorem SetTheory.PGame.quot_mul_neg (x : SetTheory.PGame) (y : SetTheory.PGame) :
                      x * -y = -x * y
                      @[simp, irreducible]
                      theorem SetTheory.PGame.quot_left_distrib (x : SetTheory.PGame) (y : SetTheory.PGame) (z : SetTheory.PGame) :
                      x * (y + z) = x * y + x * z

                      x * (y + z) is equivalent to x * y + x * z.

                      @[simp]
                      theorem SetTheory.PGame.quot_left_distrib_sub (x : SetTheory.PGame) (y : SetTheory.PGame) (z : SetTheory.PGame) :
                      x * (y - z) = x * y - x * z
                      @[simp]
                      theorem SetTheory.PGame.quot_right_distrib (x : SetTheory.PGame) (y : SetTheory.PGame) (z : SetTheory.PGame) :
                      (x + y) * z = x * z + y * z

                      (x + y) * z is equivalent to x * z + y * z.

                      @[simp]
                      theorem SetTheory.PGame.quot_right_distrib_sub (x : SetTheory.PGame) (y : SetTheory.PGame) (z : SetTheory.PGame) :
                      (y - z) * x = y * x - z * x
                      def SetTheory.PGame.mulOneRelabelling (x : SetTheory.PGame) :
                      (x * 1).Relabelling x

                      x * 1 has the same moves as x.

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        @[simp]
                        theorem SetTheory.PGame.quot_mul_one (x : SetTheory.PGame) :
                        x * 1 = x

                        x * 1 is equivalent to x.

                        def SetTheory.PGame.oneMulRelabelling (x : SetTheory.PGame) :
                        (1 * x).Relabelling x

                        1 * x has the same moves as x.

                        Equations
                        Instances For
                          @[simp]
                          theorem SetTheory.PGame.quot_one_mul (x : SetTheory.PGame) :
                          1 * x = x

                          1 * x is equivalent to x.

                          @[irreducible]
                          theorem SetTheory.PGame.quot_mul_assoc (x : SetTheory.PGame) (y : SetTheory.PGame) (z : SetTheory.PGame) :
                          x * y * z = x * (y * z)

                          x * y * z is equivalent to x * (y * z).

                          def SetTheory.PGame.mulOption (x : SetTheory.PGame) (y : SetTheory.PGame) (i : x.LeftMoves) (j : y.LeftMoves) :

                          The left options of x * y of the first kind, i.e. of the form xL * y + x * yL - xL * yL.

                          Equations
                          • x.mulOption y i j = x.moveLeft i * y + x * y.moveLeft j - x.moveLeft i * y.moveLeft j
                          Instances For
                            theorem SetTheory.PGame.mulOption_neg_neg {x : SetTheory.PGame} (y : SetTheory.PGame) {i : x.LeftMoves} {j : y.LeftMoves} :
                            x.mulOption y i j = x.mulOption (- -y) i (SetTheory.PGame.toLeftMovesNeg (SetTheory.PGame.toRightMovesNeg j))

                            Any left option of x * y of the first kind is also a left option of x * -(-y) of the first kind.

                            theorem SetTheory.PGame.mulOption_symm (x : SetTheory.PGame) (y : SetTheory.PGame) {i : x.LeftMoves} {j : y.LeftMoves} :
                            x.mulOption y i j = y.mulOption x j i

                            The left options of x * y agree with that of y * x up to equivalence.

                            theorem SetTheory.PGame.leftMoves_mul_iff {x : SetTheory.PGame} {y : SetTheory.PGame} (P : SetTheory.GameProp) :
                            (∀ (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

                            The left options of x * y of the second kind are the left options of (-x) * (-y) of the first kind, up to equivalence.

                            theorem SetTheory.PGame.rightMoves_mul_iff {x : SetTheory.PGame} {y : SetTheory.PGame} (P : SetTheory.GameProp) :
                            (∀ (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)

                            The right options of x * y are the left options of x * (-y) and of (-x) * y of the first kind, up to equivalence.

                            inductive SetTheory.PGame.InvTy (l : Type u) (r : Type u) :
                            BoolType u

                            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.

                            Instances For
                              Equations
                              Equations
                              def SetTheory.PGame.invVal {l : Type u_1} {r : Type u_1} (L : lSetTheory.PGame) (R : rSetTheory.PGame) (IHl : lSetTheory.PGame) (IHr : rSetTheory.PGame) (x : SetTheory.PGame) {b : Bool} :

                              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.

                              Equations
                              Instances For
                                @[simp]
                                theorem SetTheory.PGame.invVal_isEmpty {l : Type u} {r : Type u} {b : Bool} (L : lSetTheory.PGame) (R : rSetTheory.PGame) (IHl : lSetTheory.PGame) (IHr : rSetTheory.PGame) (i : SetTheory.PGame.InvTy l r b) (x : SetTheory.PGame) [IsEmpty l] [IsEmpty r] :
                                SetTheory.PGame.invVal L R IHl IHr x i = 0

                                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.

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

                                  inv' 0 has exactly the same moves as 1.

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

                                    inv' 1 has exactly the same moves as 1.

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

                                      The inverse of a pre-game in terms of the inverse on positive pre-games.

                                      Equations
                                      Equations
                                      def SetTheory.PGame.invOne :
                                      1⁻¹.Relabelling 1

                                      1⁻¹ has exactly the same moves as 1.

                                      Equations
                                      Instances For