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, since Lean's inductive types aren't powerful enough to express this on their own. See the docstring on GameFunctor 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.

Game moves #

@[irreducible]
def IGame :
Type (u + 1)

Well-founded games up to identity.

IGame uses the set-theoretic notion of equality on games, meaning that two IGames are equal exactly when their left and right sets of options are.

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. The quotient Game of games up to equality is defined in CombinatorialGames.Game.Basic.

More precisely, IGame is the inductive type for the single constructor

  | ofSets (s t : Set IGame.{u}) [Small.{u} s] [Small.{u} t] : IGame.{u}

(though for technical reasons it's not literally defined as such). A consequence of this is that there is no infinite line of play. See LGame for a definition of loopy games.

Equations
Instances For
    def IGame.ofSets (s t : Set IGame) [hs : Small.{u, u + 1} s] [ht : Small.{u, u + 1} t] :

    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 other game types.

    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
    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 other game types.

      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.

      Conventions for notations in identifiers:

      • The recommended spelling of {· | ·}ᴵ in identifiers is ofSets.
      Equations
      • One or more equations did not get rendered due to their size.
      Instances For

        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

            Two IGames are equal when their move sets are.

            For the weaker but more common notion of equivalence where x = y if x ≤ y and y ≤ x, use Game.

            @[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₂

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

            Equations
            Instances For
              def IGame.moveRecOn {motive : IGameSort u_1} (x : IGame) (mk : (x : IGame) → ((y : IGame) → y x.leftMovesmotive y)((y : IGame) → y x.rightMovesmotive y)motive x) :
              motive x

              Conway recursion: build data for a game by recursively building it on its left and right sets. You rarely need to use this explicitly, as the termination checker will handle things for you.

              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 {motive : IGameSort u_1} (x : IGame) (mk : (x : IGame) → ((y : IGame) → y x.leftMovesmotive y)((y : IGame) → y x.rightMovesmotive y)motive x) :
                moveRecOn x mk = mk x (fun (y : IGame) (x : y x.leftMoves) => moveRecOn y mk) fun (y : IGame) (x : y x.rightMoves) => moveRecOn y mk
                def IGame.ofSetsRecOn {motive : IGameSort u_1} (x : IGame) (mk : (s t : Set IGame) → [inst : Small.{u, u + 1} s] → [inst_1 : Small.{u, u + 1} t] → ((x : IGame) → x smotive x)((x : IGame) → x tmotive x)motive {s | t}ᴵ) :
                motive x

                Conway recursion: build data for a game by recursively building it on its left and right sets. You rarely need to use this explicitly, as the termination checker will handle things for you.

                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 {motive : IGameSort u_1} (s t : Set IGame) [Small.{u, u + 1} s] [Small.{u, u + 1} t] (mk : (s t : Set IGame) → [inst : Small.{u, u + 1} s] → [inst_1 : Small.{u, u + 1} t] → ((x : IGame) → x smotive x)((x : IGame) → x tmotive x)motive {s | t}ᴵ) :
                  ofSetsRecOn {s | t}ᴵ mk = mk s t (fun (y : IGame) (x : y s) => ofSetsRecOn y mk) fun (y : IGame) (x : y t) => ofSetsRecOn y mk

                  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

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

                      Conventions for notations in identifiers:

                      • The recommended spelling of in identifiers is lf.
                      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 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 games, in terms of .

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

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

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

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

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

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

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

                        The definition of x ⧏ 0 on 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 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 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.

                        Conventions for notations in identifiers:

                        • The recommended spelling of in identifiers is equiv.
                        Equations
                        Instances For

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

                          Conventions for notations in identifiers:

                          • The recommended spelling of in identifiers is fuzzy.
                          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_forall_lf {x y : IGame} (hl₁ : ax.leftMoves, ¬y a) (hr₁ : ax.rightMoves, ¬a y) (hl₂ : by.leftMoves, ¬x b) (hr₂ : by.rightMoves, ¬b x) :
                                xy
                                theorem IGame.equiv_of_exists_le {x y : IGame} (hl₁ : ax.leftMoves, by.leftMoves, a b) (hr₁ : ax.rightMoves, by.rightMoves, b a) (hl₂ : by.leftMoves, ax.leftMoves, b a) (hr₂ : by.rightMoves, ax.rightMoves, a b) :
                                xy
                                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 #

                                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.

                                theorem IGame.add_congr {a b : IGame} (h₁ : ab) {c d : IGame} (h₂ : cd) :
                                a + cb + d
                                theorem IGame.add_congr_left {a b c : IGame} (h : ab) :
                                a + cb + c
                                theorem IGame.add_congr_right {a b c : IGame} (h : ab) :
                                c + ac + b
                                @[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
                                theorem IGame.sub_congr {a b : IGame} (h₁ : ab) {c d : IGame} (h₂ : cd) :
                                a - cb - d
                                theorem IGame.sub_congr_left {a b c : IGame} (h : ab) :
                                a - cb - c
                                theorem IGame.sub_congr_right {a b c : IGame} (h : ab) :
                                c - ac - b

                                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 NatOrdinal.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)
                                    @[simp]
                                    theorem IGame.mulOption_zero_left (x y a : IGame) :
                                    mulOption x y 0 a = x * a
                                    @[simp]
                                    theorem IGame.mulOption_zero_right (x y a : IGame) :
                                    mulOption x y a 0 = a * y

                                    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⁻¹
                                    theorem IGame.inv_of_equiv_zero {x : IGame} (h : x0) :
                                    x⁻¹ = 0
                                    @[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