Zulip Chat Archive

Stream: new members

Topic: Well founded recursion with universes


Fox Thomson (Aug 09 2020 at 15:58):

I am attempting to prove the Spauge-Grundy theorem which I am stating as

theorem Sprague_Grundy :  (G : pgame.{u+2}) [G.impartial], inhabited { O : ordinal.{u+1} // G  nim O }

In order to prove this I need to induct on G using the pgame.pgame_wf_tac tactic and using the theorem on G.move_left i for some left move i but I am getting an error about universe levels which I think is due to the subsequent games being of type pgame.{u+1}. How can I make a more flexible universe variable?
My attempted proof and related definitions is here:

def nonmoves {α : Type _} (M : α  ordinal.{u}) : set ordinal.{u+1} := { O : ordinal | ¬  a : α, ordinal.lift.{u (u+1)} (M a) = O }

lemma nonmoves_nonempty {α : Type _} (M : α  ordinal.{u}) :  O : ordinal, O  nonmoves M :=
begin
    have h : ¬  a, ordinal.lift.{u (u+1)} (M a) = ordinal.lift.principal_seg.{u (u+1)}.top,
    rintro  a, ha ,
    have down := ordinal.lift.principal_seg.{u (u+1)}.down (ordinal.lift.{u (u+1)} (M a)),
    have h' :  (b : ordinal), ordinal.lift.principal_seg.{u (u+1)} b = (ordinal.lift.{u (u+1)} (M a)),
        use M a,
        rw ordinal.lift.principal_seg_coe,
    have hcontra := down.2 h',
    have h := (lt_iff_le_and_ne.1 hcontra).2,
    contradiction,
    use ordinal.lift.principal_seg.{u (u+1)}.top
end

theorem Sprague_Grundy :  (G : pgame.{u+2}) [G.impartial], inhabited { O : ordinal.{u+1} // G  nim O }
| G :=
begin
    classical,
    introI,
    let M := λ i, (Sprague_Grundy (G.move_left i)).default.val,
    fconstructor,
    fconstructor,
    have S := nonmoves M,
    apply ordinal.omin,
    exact nonmoves_nonempty M,
    -- exact ordinal.omin.{u+1} (nonmoves M) (nonmoves_nonempty M)
    sorry,
end

Scott Morrison (Aug 10 2020 at 01:59):

#mwe, or a branch to look at?

Scott Morrison (Aug 10 2020 at 02:00):

Without catching on what you've been doing, it's hard to say. The fact that G.impartial is a typeclass strikes me as unlikely to be a good choice, however!

Fox Thomson (Aug 10 2020 at 10:27):

@Scott Morrison I have made a GitHub repository at https://github.com/foxthomson/impartial. The problem is in src/nim.lean.

Reid Barton (Aug 10 2020 at 10:35):

Why isn't your theorem statement simply

theorem Sprague_Grundy :  (G : pgame.{u}) [G.impartial], inhabited { O : ordinal.{u} // G  nim O }

with a single universe level? I think the issue is in your definition of nim.

Reid Barton (Aug 10 2020 at 10:38):

As currently stated, the theorem is false.

Reid Barton (Aug 10 2020 at 10:39):

def nim : ordinal  pgame
| O₁ :=  { O₂ : ordinal // O₂ < O₁ },

this construction is tempting, but it blows up the universe level unnecessarily.

Fox Thomson (Aug 10 2020 at 10:40):

If O is ordinal.{u} then ordinals less than O are in the universe u. This means that nim O is in the universe u+1.

Reid Barton (Aug 10 2020 at 10:40):

Right, which is wrong.

Fox Thomson (Aug 10 2020 at 10:40):

How come?

Reid Barton (Aug 10 2020 at 10:40):

If O : ordinal.{u} then O is the order type of some type in Type u, and that's the correct universe level to be in

Reid Barton (Aug 10 2020 at 10:41):

{ O₂ : ordinal // O₂ < O₁ } has the same order type but it's in Type (u+1)

Fox Thomson (Aug 10 2020 at 10:41):

So I should try to get the order type out of the quotient?

Reid Barton (Aug 10 2020 at 10:42):

Yeah, if you can define nim directly as a game, you could try to use lift, otherwise use quot.out in some form.

Fox Thomson (Aug 10 2020 at 10:43):

Thank you, I will try

Reid Barton (Aug 10 2020 at 10:47):

Another thing you could maybe do is have nim take a well-ordered type, rather than an ordinal

Fox Thomson (Aug 10 2020 at 13:49):

I have a #mwe which does not depend on nim at all

import set_theory.ordinal
import set_theory.pgame
import tactic.nth_rewrite.default

universes u v

namespace pgame

local infix `  ` := pgame.equiv

@[class] def impartial : pgame  Prop
| G := G  -G  ( i, impartial (G.move_left i))  ( j, impartial (G.move_right j))
using_well_founded {dec_tac := pgame_wf_tac}

@[simp] lemma impartial_def {G : pgame} :
    G.impartial  G  -G  ( i, impartial (G.move_left i))  ( j, impartial (G.move_right j)) :=
begin
    split,
    {   intro hi,
        unfold1 impartial at hi,
        exact hi },
    {   intro hi,
        unfold1 impartial,
        exact hi }
end

@[instance] lemma impartial_move_left_impartial {G : pgame} [h : G.impartial] (i : G.left_moves) : impartial (G.move_left i) :=
begin
    rw impartial_def at h,
    exact h.2.1 i,
end

def nonmoves {α : Type _} (M : α  ordinal.{u}) : set ordinal.{u+1} := { O : ordinal | ¬  a : α, ordinal.lift.{u (u+1)} (M a) = O }

lemma nonmoves_nonempty {α : Type _} (M : α  ordinal.{u}) :  O : ordinal, O  nonmoves M :=
begin
    have h : ¬  a, ordinal.lift.{u (u+1)} (M a) = ordinal.lift.principal_seg.{u (u+1)}.top,
    rintro  a, ha ,
    have down := ordinal.lift.principal_seg.{u (u+1)}.down (ordinal.lift.{u (u+1)} (M a)),
    have h' :  (b : ordinal), ordinal.lift.principal_seg.{u (u+1)} b = (ordinal.lift.{u (u+1)} (M a)),
        use M a,
        rw ordinal.lift.principal_seg_coe,
    have hcontra := down.2 h',
    have h := (lt_iff_le_and_ne.1 hcontra).2,
    contradiction,
    use ordinal.lift.principal_seg.{u (u+1)}.top
end

def Grundy_value : Π (G : pgame.{u}) [G.impartial], ordinal.{u+1}
| G :=
begin
    introI,
    let M := λ i, Grundy_value (G.move_left i),
    exact ordinal.omin (nonmoves M) (nonmoves_nonempty M),
end

end pgame

I am getting an error as M in Grundy_value is of the form G.left_moves -> ordinal.{u+1} so nonmoves M is a set of ordinal.{u+2} a universe too big. I think I am loking for a way to write ordinal.{2*u}

Fox Thomson (Aug 10 2020 at 14:04):

Actually I think it is due to Grundy_value not stepping down a universe when it is used recursively, Lean has understood M as a function from G.left_moves to ordinal.{u+1} when I want it to be sent to ordinal.{u}

Reid Barton (Aug 10 2020 at 14:05):

Well you wrote Π (G : pgame.{u}) [G.impartial], ordinal.{u+1}--it should take values in ordinal.{u}

Fox Thomson (Aug 10 2020 at 14:05):

Which should work as G.move_left i is a member of pgame.{u-1}

Reid Barton (Aug 10 2020 at 14:06):

As the type of Grundy_value I mean

Fox Thomson (Aug 10 2020 at 14:07):

I want it to take values in the universe u understood as a variable so I can call it with each universe a level down

Reid Barton (Aug 10 2020 at 14:07):

You can't do recursion with varying universe levels, but in any case, the Grundy value of a game is supposed to be an ordinal in the same universe as the game

Reid Barton (Aug 10 2020 at 14:08):

for example an "ordinary" game is one that lives in universe level 0, and its Grundy value is an ordinary ordinal which also lives in universe level 0

Fox Thomson (Aug 10 2020 at 14:10):

But if I have shown that all ordinary games have a Grundy value shouldn't I be able to access their Grundy value viewed as an ordinary ordinal when talking about universe 1 games?

Reid Barton (Aug 10 2020 at 14:10):

Lean doesn't work that way

Reid Barton (Aug 10 2020 at 14:11):

I agree in normal math you could do it

Fox Thomson (Aug 10 2020 at 14:11):

Is there any known tricks to get around this?

Reid Barton (Aug 10 2020 at 14:11):

I claim it's impossible to actually have this problem in Lean

Reid Barton (Aug 10 2020 at 14:11):

actually I'm not really sure whether that is true

Reid Barton (Aug 10 2020 at 14:12):

but if you have this problem then something went wrong earlier

Reid Barton (Aug 10 2020 at 14:16):

Why would you need this?

Fox Thomson (Aug 10 2020 at 14:16):

The S-G theorem requires nonmoves to be able to find the mex. This requires nonmoves to be nonempty so nonmoves has to be defined as a set of ordinal.{u+1} otherwise we could feed it the identity function on ordinal.{u} and it would be empty.

Reid Barton (Aug 10 2020 at 14:17):

I think nonmoves also has the wrong result universe level, it should be set ordinal.{u}.

Fox Thomson (Aug 10 2020 at 14:18):

This means that the Grundy value has to be strictly universe higher than the Grundy value of all subsequent games

Reid Barton (Aug 10 2020 at 14:18):

There's no way to index all of ordinal.{u} with a Type u-sized family--but there is a theorem to be proved here!

Reid Barton (Aug 10 2020 at 14:18):

No, you can't do it that way in Lean (and you wouldn't do it that way in math either)

Reid Barton (Aug 10 2020 at 14:18):

Only one universe is needed

Reid Barton (Aug 10 2020 at 14:19):

The classical way to describe the situation would be: to an impartial game we assign the least ordinal which is not the value of any option of the game; such an ordinal exists because ordinals form a proper class but the options of the game only form a set.

Fox Thomson (Aug 10 2020 at 14:20):

Oh, so saying alpha is type u means that nonmoves is nonempty without jumping up a universe

Reid Barton (Aug 10 2020 at 14:22):

I think there's a theorem to this effect somewhere in set_theory.ordinal or set_theory.cardinal

Mario Carneiro (Aug 10 2020 at 19:21):

I tried to make an API for this sort of construction, but I wasn't able to make anything sufficiently general to cover all the use cases. But you can get a type with the order type of the ordinal using quot.out, and use that

Mario Carneiro (Aug 10 2020 at 19:23):

o.out.α has the right size


Last updated: Dec 20 2023 at 11:08 UTC