Documentation

CombinatorialGames.Game.Loopy.Basic

Loopy games #

The standard notion of a game studied in combinatorial game theory is that of a terminating game, meaning that there exists no infinite sequence of moves. Loopy games relax this condition by allowing "self-refential" games, with the basic examples being on = {on | }, off = { | off}, and dud = {dud | dud}.

In the literature, loopy games are defined as rooted directed graphs up to isomorphism. However, it's simpler to define LGame as the coinductive type for the single constructor:

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

(The inductive type for this same constructor would be IGame.) This gives us a powerful corecursion principle LGame.corec, which can be interpreted as saying "for any graph we can draw on a type α, as long as the amount of branches per node is u-small, there's an LGame isomorphic to it".

Although extensionality still holds, it's not always sufficient to prove two games equal. For instance, if x = !{x | x} and y = !{y | y}, then x = y, but trying to use extensionality to prove this just leads to a cyclic argument. Instead, we can use LGame.eq_of_bisim, which can roughly be interpreted as saying "if two games have the same shape, they're equal". In this case, the relation r a b ↔ a = x ∧ b = y is a bisimulation between both games, which proves their equality.

For Mathlib #

theorem QPF.Cofix.unique {F : Type u → Type u} [QPF F] {α : Type u} (a : αF α) (f g : αCofix F) (hf : dest f = Functor.map f a) (hg : dest g = Functor.map g a) :
f = g

Game moves #

@[irreducible]
def LGame :
Type (u_1 + 1)

The type of loopy games.

Most games studied within game theory are terminating, which means that the IsOption relation is well-founded. A loopy game relaxes this constraint. Thus, LGame contains all normal IGames, but it also contains games such as on = {on | }, off = { | off}, and dud = {dud | dud}.

See the module docstring for guidance on how to make use of this type.

Equations
Instances For
    def LGame.moves (p : Player) (x : LGame) :

    The set of moves of the game.

    Equations
    Instances For

      The set of left moves of the game.

      Equations
      Instances For

        The set of right moves of the game.

        Equations
        Instances For

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

          Equations
          Instances For
            theorem LGame.IsOption.of_mem_moves {p : Player} {x y : LGame} (h : x moves p y) :

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

            Equations
            Instances For
              theorem LGame.Subposition.of_mem_moves {p : Player} {x y : LGame} (h : x moves p y) :
              theorem LGame.Subposition.trans {x y z : LGame} (h₁ : x.Subposition y) (h₂ : y.Subposition z) :
              theorem LGame.eq_of_bisim (r : LGameLGameProp) (H : ∀ (x y : LGame), r x y∀ (p : Player), ∃ (s : Set (LGame × LGame)), Prod.fst '' s = moves p x Prod.snd '' s = moves p y zs, r z.1 z.2) {x y : LGame} (hxy : r x y) :
              x = y

              Two loopy games are equal when there exists a bisimulation between them.

              A way to think about this is that r defines a pairing between nodes of the game trees, which then shows that the trees are isomorphic.

              theorem LGame.ext {x y : LGame} (h : ∀ (p : Player), moves p x = moves p y) :
              x = y

              Two LGames are equal when their move sets are.

              This is not always sufficient to prove that two games are equal. For instance, if x = !{x | x} and y = !{y | y}, then x = y, but trying to use extensionality to prove this just leads to a cyclic argument. For these situations, you can use eq_of_bisim instead.

              theorem LGame.ext_iff {x y : LGame} :
              x = y ∀ (p : Player), moves p x = moves p y
              def LGame.corec {α : Type v} (mov : PlayerαSet α) [∀ (a : α), Small.{u, v} (mov left a)] [∀ (a : α), Small.{u, v} (mov right a)] (init : α) :

              The corecursor on LGame.

              You can use this in order to define an arbitrary LGame by "drawing" its move graph on some other type. As an example, on = !{on | } is defined as corec (Player.cases ⊤ ⊥) ().

              Equations
              Instances For
                @[simp]
                theorem LGame.moves_corec {α : Type v} (p : Player) (mov : PlayerαSet α) [∀ (a : α), Small.{u, v} (mov left a)] [∀ (a : α), Small.{u, v} (mov right a)] (init : α) :
                moves p (corec mov init) = corec mov '' mov p init
                theorem LGame.moves_comp_corec {α : Type v} (p : Player) (mov : PlayerαSet α) [∀ (a : α), Small.{u, v} (mov left a)] [∀ (a : α), Small.{u, v} (mov right a)] :
                moves p corec mov = Set.image (corec mov) mov p
                theorem LGame.hom_unique_apply {α : Type v} {mov : PlayerαSet α} [∀ (a : α), Small.{u, v} (mov left a)] [∀ (a : α), Small.{u, v} (mov right a)] (f g : αLGame) (hf : ∀ (p : Player), moves p f = Set.image f mov p) (hg : ∀ (p : Player), moves p g = Set.image g mov p) (x : α) :
                f x = g x
                theorem LGame.hom_unique {α : Type v} {mov : PlayerαSet α} [∀ (a : α), Small.{u, v} (mov left a)] [∀ (a : α), Small.{u, v} (mov right a)] (f g : αLGame) (hf : ∀ (p : Player), moves p f = Set.image f mov p) (hg : ∀ (p : Player), moves p g = Set.image g mov p) :
                f = g
                theorem LGame.corec_comp_hom {α : Type v} {β : Type w} {movα : PlayerαSet α} {movβ : PlayerβSet β} [∀ (a : α), Small.{u, v} (movα left a)] [∀ (a : α), Small.{u, v} (movα right a)] [∀ (b : β), Small.{u, w} (movβ left b)] [∀ (b : β), Small.{u, w} (movβ right b)] (f : αβ) (hf : ∀ (p : Player), movβ p f = Set.image f movα p) :
                corec movβ f = corec movα
                theorem LGame.corec_comp_hom_apply {α : Type v} {β : Type w} {movα : PlayerαSet α} {movβ : PlayerβSet β} [∀ (a : α), Small.{u, v} (movα left a)] [∀ (a : α), Small.{u, v} (movα right a)] [∀ (b : β), Small.{u, w} (movβ left b)] [∀ (b : β), Small.{u, w} (movβ right b)] (f : αβ) (hf : ∀ (p : Player), movβ p f = Set.image f movα p) (x : α) :
                corec movβ (f x) = corec movα x
                instance LGame.instOfSetsTrue :
                OfSets LGame fun (x : PlayerSet LGame) => True

                Construct an LGame from its left and right sets.

                It's not possible to create a non-well-founded game through this constructor alone. For that, see LGame.corec.

                Equations
                • One or more equations did not get rendered due to their size.
                @[simp]
                theorem LGame.moves_ofSets (p : Player) (lr : PlayerSet LGame) [Small.{u, u + 1} (lr left)] [Small.{u, u + 1} (lr right)] :
                moves p !{lr} = lr p

                Basic games #

                The game 0 = !{∅ | ∅}.

                Equations
                theorem LGame.zero_def :
                0 = !{fun (x : Player) => }
                @[simp]
                theorem LGame.moves_zero (p : Player) :
                moves p 0 =

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

                Equations
                theorem LGame.one_def :
                1 = !{{0} | }

                The game on = !{{on} | ∅}.

                Equations
                Instances For
                  @[simp]
                  theorem LGame.on_eq :
                  on = !{{on} | }

                  The game off = !{∅ | {off}}.

                  Equations
                  Instances For

                    The game dud = !{{dud} | {dud}}.

                    Equations
                    Instances For
                      @[simp]

                      The game tis = !{{tisn} | ∅}, where tisn = !{∅ | {tis}}.

                      Equations
                      Instances For

                        The game tisn = !{∅ | {tis}}, where tis = !{{tisn} | ∅}.

                        Equations
                        Instances For

                          Negation #

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

                          Equations
                          @[simp]
                          theorem LGame.corec_moves_neg :
                          (corec fun (p : Player) => moves (-p)) = fun (x : LGame) => -x
                          theorem LGame.corec_moves_neg_apply (x : LGame) :
                          corec (fun (p : Player) => moves (-p)) x = -x
                          theorem LGame.neg_corec {α : Type v} (mov : PlayerαSet α) [∀ (x : α), Small.{u, v} (mov left x)] [∀ (x : α), Small.{u, v} (mov right x)] :
                          -corec mov = corec fun (p : Player) => mov (-p)
                          theorem LGame.neg_corec_apply {α : Type v} (mov : PlayerαSet α) [∀ (x : α), Small.{u, v} (mov left x)] [∀ (x : α), Small.{u, v} (mov right x)] (init : α) :
                          -corec mov init = corec (fun (p : Player) => mov (-p)) init
                          @[simp]
                          theorem LGame.moves_neg (p : Player) (x : LGame) :
                          moves p (-x) = -moves (-p) x
                          @[simp]
                          theorem LGame.neg_ofSets (s t : Set LGame) [Small.{u, u + 1} s] [Small.{u, u + 1} t] :
                          -!{s | t} = !{-t | -s}
                          theorem LGame.neg_ofSets' (st : PlayerSet LGame) [Small.{u_1, u_1 + 1} (st left)] [Small.{u_1, u_1 + 1} (st right)] :
                          -!{st} = !{fun (p : Player) => -st (-p)}
                          @[simp]
                          theorem LGame.neg_ofSets_const (s : Set LGame) [Small.{u_1, u_1 + 1} s] :
                          -!{fun (x : Player) => s} = !{fun (x : Player) => -s}
                          @[simp]
                          @[simp]
                          @[simp]
                          @[simp]
                          @[simp]

                          Addition #

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

                          Equations
                          • One or more equations did not get rendered due to their size.
                          theorem LGame.corec_add_corec {α : Type v} {β : Type w} {movα : PlayerαSet α} {movβ : PlayerβSet β} [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (initα : α) (initβ : β) :
                          corec movα initα + corec movβ initβ = corec (fun (p : Player) (x : α × β) => (fun (y : α) => (y, x.2)) '' movα p x.1 (fun (y : β) => (x.1, y)) '' movβ p x.2) (initα, initβ)
                          @[simp]
                          theorem LGame.moves_add (p : Player) (x y : LGame) :
                          moves p (x + y) = (fun (x : LGame) => x + y) '' moves p x (fun (x_1 : LGame) => x + x_1) '' moves p y
                          @[simp]
                          theorem LGame.add_eq_zero_iff {x y : LGame} :
                          x + y = 0 x = 0 y = 0
                          Equations
                          • One or more equations did not get rendered due to their size.
                          @[simp]
                          @[simp]
                          @[simp]
                          theorem LGame.add_dud (x : LGame) :
                          @[simp]
                          theorem LGame.dud_add (x : LGame) :
                          theorem LGame.moves_sum (p : Player) (m : Multiset LGame) :
                          moves p m.sum = ym, (fun (x : LGame) => x + (m.erase y).sum) '' moves p y

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

                          Equations
                          • One or more equations did not get rendered due to their size.
                          theorem LGame.corec_sub_corec {α : Type v} {β : Type w} {movα : PlayerαSet α} {movβ : PlayerβSet β} [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (initα : α) (initβ : β) :
                          corec movα initα - corec movβ initβ = corec (fun (p : Player) (x : α × β) => (fun (y : α) => (y, x.2)) '' movα p x.1 (fun (y : β) => (x.1, y)) '' movβ (-p) x.2) (initα, initβ)
                          @[simp]
                          theorem LGame.moves_sub (p : Player) (x y : LGame) :
                          moves p (x - y) = (fun (x : LGame) => x - y) '' moves p x (fun (x_1 : LGame) => x + x_1) '' (-moves (-p) y)
                          Equations
                          • One or more equations did not get rendered due to their size.
                          @[simp]
                          @[simp]
                          theorem LGame.sub_dud (x : LGame) :

                          Multiplication #

                          @[reducible, inline]
                          abbrev LGame.MulTy (α : Type u_1) (β : Type u_2) :
                          Type (max u_2 u_1)

                          Given two game graphs drawn on types α and β, the graph for the product can be drawn on the type Multiset (Player × α × β). Each term corresponds to a sum Σ ±aᵢ * bᵢ, where aᵢ and bᵢ are terms of α and β respectively, and the attached player represents each term's sign.

                          Equations
                          Instances For
                            instance LGame.MulTy.instInvolutiveNeg {α : Type v} {β : Type w} :

                            Inverts the sign of all entries.

                            Equations
                            theorem LGame.MulTy.neg_def {α : Type v} {β : Type w} (x : MulTy α β) :
                            -x = Multiset.map (fun (y : Player × α × β) => (-y.1, y.2)) x
                            @[simp]
                            theorem LGame.MulTy.mem_neg {α : Type v} {β : Type w} {x : Player × α × β} {y : MulTy α β} :
                            x -y (-x.1, x.2) y
                            @[simp]
                            theorem LGame.MulTy.neg_zero {α : Type v} {β : Type w} :
                            -0 = 0
                            @[simp]
                            theorem LGame.MulTy.neg_singleton {α : Type v} {β : Type w} (a : Player × α × β) :
                            -{a} = {(-a.1, a.2)}
                            @[simp]
                            theorem LGame.MulTy.neg_cons {α : Type v} {β : Type w} (a : Player × α × β) (x : MulTy α β) :
                            -(a ::ₘ x) = (-a.1, a.2) ::ₘ -x
                            @[simp]
                            theorem LGame.MulTy.neg_add {α : Type v} {β : Type w} (x y : MulTy α β) :
                            -(x + y) = -x + -y
                            @[simp]
                            theorem LGame.MulTy.neg_erase {α : Type v} {β : Type w} [DecidableEq α] [DecidableEq β] (x : MulTy α β) (a : Player × α × β) :
                            def LGame.MulTy.swap {α : Type v} {β : Type w} (x : MulTy α β) :
                            MulTy β α

                            Swaps the entries in all pairs.

                            Equations
                            Instances For
                              theorem LGame.MulTy.swap_def {α : Type v} {β : Type w} (x : MulTy α β) :
                              x.swap = Multiset.map (fun (a : Player × α × β) => (a.1, a.2.swap)) x
                              @[simp]
                              theorem LGame.MulTy.mem_swap {α : Type v} {β : Type w} {x : Player × β × α} {y : MulTy α β} :
                              x y.swap (x.1, x.2.swap) y
                              @[simp]
                              theorem LGame.MulTy.swap_zero {α : Type v} {β : Type w} :
                              swap 0 = 0
                              @[simp]
                              theorem LGame.MulTy.swap_singleton {α : Type v} {β : Type w} (a : Player × α × β) :
                              {a}.swap = {(a.1, a.2.swap)}
                              @[simp]
                              theorem LGame.MulTy.swap_cons {α : Type v} {β : Type w} (a : Player × α × β) (x : MulTy α β) :
                              swap (a ::ₘ x) = (a.1, a.2.swap) ::ₘ x.swap
                              @[simp]
                              theorem LGame.MulTy.swap_add {α : Type v} {β : Type w} (x y : MulTy α β) :
                              (x + y).swap = x.swap + y.swap
                              @[simp]
                              theorem LGame.MulTy.swap_erase {α : Type v} {β : Type w} [DecidableEq α] [DecidableEq β] (x : MulTy α β) (a : Player × α × β) :
                              def LGame.MulTy.mulOption {α : Type v} {β : Type w} (p : Player) (x y : α × β) :
                              MulTy α β

                              The general form of an option of x * y is a * y + x * b - a * b.

                              If the player argument is left, all signs are flipped.

                              Equations
                              Instances For
                                @[simp]
                                theorem LGame.MulTy.neg_mulOption {α : Type v} {β : Type w} (p : Player) (x y : α × β) :
                                -mulOption p x y = mulOption (-p) x y
                                @[simp]
                                theorem LGame.MulTy.swap_mulOption {α : Type v} {β : Type w} (p : Player) (x y : α × β) :
                                theorem LGame.MulTy.mulOption_eq_add {α : Type v} {β : Type w} (p : Player) (x y : α × β) :
                                mulOption p x y = {(p, y.1, x.2)} + {(p, x.1, y.2)} + {(-p, y.1, y.2)}
                                def LGame.MulTy.movesSet {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) (x : Player × α × β) :
                                Set (α × β)

                                The set of pairs α × β used in movesSingle.

                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For
                                  theorem LGame.MulTy.movesSet_neg {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) (x : Player × α × β) :
                                  movesSet p movα movβ (-x.1, x.2) = movesSet (-p) movα movβ x
                                  theorem LGame.MulTy.movesSet_neg' (p : Player) (x : Player × LGame × LGame) :
                                  movesSet p moves moves (x.1, -x.2.1, x.2.2) = (fun (y : LGame × LGame) => (-y.1, y.2)) '' movesSet (-p) moves moves x
                                  theorem LGame.MulTy.movesSet_swap {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) (x : Player × α × β) :
                                  movesSet p movβ movα (x.1, x.2.swap) = Prod.swap '' movesSet p movα movβ x
                                  def LGame.MulTy.movesSingle {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) (x : Player × α × β) :
                                  Set (MulTy α β)

                                  The left or right moves of ±x * y are left or right moves of x * y if the sign is positive, or the negatives of right or left moves of x * y if the sign is negative.

                                  Equations
                                  Instances For
                                    theorem LGame.MulTy.movesSingle_neg {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) (x : Player × α × β) :
                                    movesSingle p movα movβ (-x.1, x.2) = -movesSingle (-p) movα movβ x
                                    theorem LGame.MulTy.movesSingle_swap {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) (x : Player × α × β) :
                                    movesSingle p movβ movα (x.1, x.2.swap) = swap '' movesSingle p movα movβ x
                                    def LGame.MulTy.moves {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] (x : MulTy α β) :
                                    Set (MulTy α β)

                                    The set of left or right moves of Σ ±xᵢ * yᵢ are zᵢ + Σ ±xⱼ * yⱼ for all i, where cᵢ is a left or right move of ±xᵢ * yᵢ, and the summation is taken over indices j ≠ i.

                                    Equations
                                    Instances For
                                      theorem Multiset.iUnion_map {α : Type u_1} {β : Type u_2} {γ : Type u_3} (m : Multiset α) (f : αβ) (g : βSet γ) :
                                      xmap f m, g x = xm, g (f x)
                                      theorem LGame.MulTy.moves_neg {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] (x : MulTy α β) :
                                      MulTy.moves p movα movβ (-x) = -MulTy.moves (-p) movα movβ x
                                      theorem LGame.MulTy.moves_neg' (p : Player) (x : MulTy LGame LGame) :
                                      MulTy.moves p moves moves (Multiset.map (fun (y : Player × LGame × LGame) => (y.1, -y.2.1, y.2.2)) x) = (Multiset.map fun (y : Player × LGame × LGame) => (y.1, -y.2.1, y.2.2)) '' MulTy.moves (-p) moves moves x
                                      theorem LGame.MulTy.moves_swap {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] (x : MulTy α β) :
                                      MulTy.moves p movβ movα x.swap = swap '' MulTy.moves p movα movβ x
                                      def LGame.MulTy.map {α₁ : Type u_1} {β₁ : Type u_2} {α₂ : Type u_3} {β₂ : Type u_4} (f : α₁α₂) (g : β₁β₂) :
                                      MulTy α₁ β₁MulTy α₂ β₂

                                      Map MulTy α₁ β₁ to MulTy α₂ β₂ using f : α₁ → α₂ and g : β₁ → β₂ in the natural way.

                                      Equations
                                      Instances For
                                        @[simp]
                                        theorem LGame.MulTy.map_add {α₁ : Type u_1} {β₁ : Type u_2} {α₂ : Type u_3} {β₂ : Type u_4} (f : α₁α₂) (g : β₁β₂) (x y : MulTy α₁ β₁) :
                                        map f g (x + y) = map f g x + map f g y
                                        theorem LGame.MulTy.map_erase {α₁ : Type u_1} {β₁ : Type u_2} {α₂ : Type u_3} {β₂ : Type u_4} (f : α₁α₂) (g : β₁β₂) [DecidableEq α₁] [DecidableEq β₁] [DecidableEq α₂] [DecidableEq β₂] {x : MulTy α₁ β₁} {y : Player × α₁ × β₁} (hy : y x) :
                                        map f g (Multiset.erase x y) = Multiset.erase (map f g x) (y.1, f y.2.1, g y.2.2)
                                        @[simp]
                                        theorem LGame.MulTy.map_mulOption {α₁ : Type u_1} {β₁ : Type u_2} {α₂ : Type u_3} {β₂ : Type u_4} (f : α₁α₂) (g : β₁β₂) (b : Player) (x y : α₁ × β₁) :
                                        map f g (mulOption b x y) = mulOption b (Prod.map f g x) (Prod.map f g y)
                                        theorem LGame.MulTy.movesSingle_comp_prodMap {p : Player} {α₁ : Type u_1} {β₁ : Type u_2} {α₂ : Type u_3} {β₂ : Type u_4} {movα₁ : Playerα₁Set α₁} {movβ₁ : Playerβ₁Set β₁} {movα₂ : Playerα₂Set α₂} {movβ₂ : Playerβ₂Set β₂} {f : α₁α₂} {g : β₁β₂} (hf : ∀ (p : Player), movα₂ p f = Set.image f movα₁ p) (hg : ∀ (p : Player), movβ₂ p g = Set.image g movβ₁ p) :
                                        movesSingle p movα₂ movβ₂ Prod.map id (Prod.map f g) = Set.image (map f g) movesSingle p movα₁ movβ₁
                                        theorem LGame.MulTy.moves_comp_map {p : Player} {α₁ : Type u_1} {β₁ : Type u_2} {α₂ : Type u_3} {β₂ : Type u_4} {movα₁ : Playerα₁Set α₁} {movβ₁ : Playerβ₁Set β₁} {movα₂ : Playerα₂Set α₂} {movβ₂ : Playerβ₂Set β₂} {f : α₁α₂} {g : β₁β₂} [Hα₁ : DecidableEq α₁] [Hβ₁ : DecidableEq β₁] [Hα₂ : DecidableEq α₂] [Hβ₂ : DecidableEq β₂] (hf : ∀ (p : Player), movα₂ p f = Set.image f movα₁ p) (hg : ∀ (p : Player), movβ₂ p g = Set.image g movβ₁ p) :
                                        MulTy.moves p movα₂ movβ₂ map f g = Set.image (map f g) MulTy.moves p movα₁ movβ₁
                                        instance LGame.MulTy.instSmallElemMovesSingle {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (x : Player × α × β) :
                                        Small.{u, max v w} (movesSingle p movα movβ x)
                                        instance LGame.MulTy.instSmallElemMoves {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (x : MulTy α β) :
                                        Small.{u, max v w} (MulTy.moves p movα movβ x)
                                        @[reducible, inline]
                                        abbrev LGame.MulTy.toLGame {α : Type v} {β : Type w} (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (x : Player × α × β) :

                                        The game ±xᵢ * yᵢ.

                                        Equations
                                        Instances For
                                          theorem LGame.MulTy.moves_toLGame {α : Type v} {β : Type w} (p : Player) (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (x : Player × α × β) :
                                          moves p (toLGame movα movβ x) = (corec fun (x : Player) => MulTy.moves x movα movβ) '' movesSingle p movα movβ x
                                          @[simp]
                                          theorem LGame.MulTy.corec_zero {α : Type v} {β : Type w} (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] :
                                          corec (fun (x : Player) => MulTy.moves x movα movβ) 0 = 0
                                          theorem LGame.MulTy.corec_neg {α : Type v} {β : Type w} (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (init : MulTy α β) :
                                          corec (fun (x : Player) => MulTy.moves x movα movβ) (-init) = -corec (fun (x : Player) => MulTy.moves x movα movβ) init
                                          theorem LGame.MulTy.corec_add {α : Type v} {β : Type w} (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (init₁ init₂ : MulTy α β) :
                                          corec (fun (x : Player) => MulTy.moves x movα movβ) (init₁ + init₂) = corec (fun (x : Player) => MulTy.moves x movα movβ) init₁ + corec (fun (x : Player) => MulTy.moves x movα movβ) init₂
                                          theorem LGame.MulTy.corec_mulOption {α : Type v} {β : Type w} (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (p : Player) (x y : α × β) :
                                          corec (fun (x : Player) => MulTy.moves x movα movβ) (mulOption p x y) = toLGame movα movβ (p, y.1, x.2) + toLGame movα movβ (p, x.1, y.2) - toLGame movα movβ (p, y.1, y.2)
                                          theorem LGame.corec_mulTy {α : Type v} {β : Type w} (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (x : MulTy α β) :
                                          corec (fun (x : Player) => MulTy.moves x movα movβ) x = (Multiset.map (MulTy.toLGame movα movβ) x).sum
                                          theorem LGame.MulTy.corec_swap {α : Type v} {β : Type w} (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (x : MulTy α β) :
                                          corec (fun (x : Player) => MulTy.moves x movβ movα) x.swap = corec (fun (x : Player) => MulTy.moves x movα movβ) x

                                          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 LGame.mulOption, this can alternatively be written as x * y = !{mulOption x y a₁ b₁ | mulOption x y a₂ b₂}.

                                          Equations
                                          theorem LGame.corec_mul_corec {α : Type v} {β : Type w} (movα : PlayerαSet α) (movβ : PlayerβSet β) [ : DecidableEq α] [ : DecidableEq β] [∀ (x : α), Small.{u, v} (movα left x)] [∀ (x : α), Small.{u, v} (movα right x)] [∀ (x : β), Small.{u, w} (movβ left x)] [∀ (x : β), Small.{u, w} (movβ right x)] (initα : α) (initβ : β) :
                                          corec movα initα * corec movβ initβ = MulTy.toLGame movα movβ (right, initα, initβ)
                                          def LGame.mulOption (x y a b : LGame) :

                                          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
                                            @[simp]
                                            theorem LGame.moves_mul (p : Player) (x y : LGame) :
                                            moves p (x * y) = (fun (a : LGame × LGame) => mulOption x y a.1 a.2) '' (moves left x ×ˢ moves p y moves right x ×ˢ moves (-p) y)
                                            @[simp]
                                            theorem LGame.moves_mulOption (p : Player) (x y a b : LGame) :
                                            moves p (mulOption x y a b) = moves p (a * y + x * b - a * b)

                                            Stoppers #

                                            inductive LGame.StopperFor :
                                            PlayerLGameProp

                                            A game is a stopper for player p when an alternating sequence of moves starting with said player always terminates.

                                            Instances For
                                              theorem LGame.stopperFor_iff (a✝ : Player) (a✝¹ : LGame) :
                                              StopperFor a✝ a✝¹ ymoves a✝ a✝¹, StopperFor (-a✝) y
                                              theorem LGame.StopperFor.of_mem_moves {p : Player} {x y : LGame} (h : StopperFor p x) (hy : y moves p x) :
                                              theorem LGame.StopperFor.neg {p : Player} {x : LGame} (h : StopperFor p x) :
                                              StopperFor (-p) (-x)
                                              @[simp]

                                              A game is a stopper when it's StopperFor for both players.

                                              Equations
                                              Instances For
                                                @[simp]
                                                theorem LGame.Stopper.stopperFor (p : Player) {x : LGame} (h : x.Stopper) :
                                                theorem LGame.Stopper.mk {x : LGame} (H : ∀ (p : Player), ymoves p x, y.Stopper) :

                                                A game is a stopper when all its options are stoppers.

                                                Note that this is not an iff, as e.g. { | { | dud}} is a stopper, but { | dud} isn't.

                                                theorem LGame.Stopper.neg {x : LGame} (h : x.Stopper) :
                                                @[simp]