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 #
Game moves #
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 IGame
s, 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
Equations
A (proper) subposition is any game in the transitive closure of IsOption
.
Instances For
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.
Two LGame
s 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.
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 ⊤ ⊥ ()
.
Equations
- LGame.corec leftMoves rightMoves init = LGame.corec'✝ leftMoves rightMoves init ⟨init, ⋯⟩
Instances For
Construct an LGame
from its left and right sets.
This is given notation {s | t}ᴸ
, where the superscript L
is to disambiguate from set builder
notation, and from the analogous constructors on other game types.
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.
Instances For
Construct an LGame
from its left and right sets.
This is given notation {s | t}ᴸ
, where the superscript L
is to disambiguate from set builder
notation, and from the analogous constructors on other game types.
It's not possible to create a non-well-founded game through this constructor alone. For that,
see LGame.corec
.
Conventions for notations in identifiers:
- The recommended spelling of
{· | ·}ᴸ
in identifiers isofSets
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Basic games #
Negation #
The negative of a game is defined by -{s | t}ᴸ = {-t | -s}ᴸ
.
Equations
Equations
- LGame.instInvolutiveNeg = { toNeg := LGame.instNeg, neg_neg := LGame.instInvolutiveNeg._proof_1 }
Equations
- LGame.instNegZeroClass = { toZero := LGame.instZero, toNeg := LGame.instNeg, neg_zero := LGame.instNegZeroClass._proof_1 }
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.
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.
Equations
- One or more equations did not get rendered due to their size.
Multiplication #
Given two game graphs drawn on types α
and β
, the graph for the product can be drawn on the
type Multiset (Bool × α × β)
. Each term corresponds to a sum Σ ±aᵢ * bᵢ
, where aᵢ
and bᵢ
are
terms of α
and β
respectively, and the attached bool represents each term's sign.
Instances For
Inverts the sign of all entries.
Equations
- LGame.MulTy.instInvolutiveNeg = { neg := fun (x : LGame.MulTy α β) => Multiset.map (fun (y : Bool × α × β) => (!y.1, y.2)) x, neg_neg := ⋯ }
The general form of an option of x * y
is a * y + x * b - a * b
.
If the boolean argument is false, all signs are flipped.
Instances For
The set of pairs α × β
used in rightMovesSingle
.
Equations
- LGame.MulTy.rightMovesSet leftMovesα rightMovesα leftMovesβ rightMovesβ x = LGame.MulTy.leftMovesSet leftMovesα rightMovesα leftMovesβ rightMovesβ (!x.1, x.2)
Instances For
The left moves of ±x * y
are left moves of x * y
if the sign is positive, or the
negatives of right moves of x * y
if the sign is negative.
Equations
- LGame.MulTy.leftMovesSingle leftMovesα rightMovesα leftMovesβ rightMovesβ x = LGame.MulTy.mulOption x.1 x.2 '' LGame.MulTy.leftMovesSet leftMovesα rightMovesα leftMovesβ rightMovesβ x
Instances For
The right moves of ±x * y
are right moves of x * y
if the sign is positive, or the
negatives of left moves of x * y
if the sign is negative.
Equations
- LGame.MulTy.rightMovesSingle leftMovesα rightMovesα leftMovesβ rightMovesβ x = LGame.MulTy.mulOption x.1 x.2 '' LGame.MulTy.rightMovesSet leftMovesα rightMovesα leftMovesβ rightMovesβ x
Instances For
The set of left moves of Σ ±xᵢ * yᵢ
are zᵢ + Σ ±xⱼ * yⱼ
for all i
, where cᵢ
is a left
move of ±xᵢ * yᵢ
, and the summation is taken over indices j ≠ i
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The set of right moves of Σ ±xᵢ * yᵢ
are zᵢ + Σ ±xⱼ * yⱼ
for all i
, where cᵢ
is a right
move of ±xᵢ * yᵢ
, and the summation is taken over indices j ≠ i
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Map MulTy α₁ β₁
to MulTy α₂ β₂
using f : α₁ → α₂
and g : β₁ → β₂
in the natural way.
Equations
- LGame.MulTy.map f g = Multiset.map (Prod.map id (Prod.map f g))
Instances For
The game ±xᵢ * yᵢ
.
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 LGame.mulOption
, this can alternatively be written as
x * y = {mulOption x y a₁ b₁ | mulOption x y a₂ b₂}ᴵ
.
Equations
- LGame.instMul = { mul := fun (x y : LGame) => LGame.MulTy.toLGame LGame.leftMoves LGame.rightMoves LGame.leftMoves LGame.rightMoves (true, x, y) }
Equations
- LGame.instCommMagma = { toMul := LGame.instMul, mul_comm := LGame.instCommMagma._proof_1 }
Equations
- LGame.instMulZeroClass = { toMul := LGame.instMul, toZero := LGame.instZero, zero_mul := LGame.instMulZeroClass._proof_1, mul_zero := LGame.instMulZeroClass._proof_2 }
Equations
- LGame.instMulOneClass = { toOne := LGame.instOne, toMul := LGame.instMul, one_mul := LGame.one_mul'✝, mul_one := LGame.instMulOneClass._proof_1 }
Equations
- LGame.instHasDistribNeg = { toInvolutiveNeg := LGame.instInvolutiveNeg, neg_mul := LGame.neg_mul'✝, mul_neg := LGame.instHasDistribNeg._proof_1 }