Zulip Chat Archive

Stream: mathlib4

Topic: wlog #16495


Johan Commelin (Sep 13 2022 at 09:21):

Since wlog is now a much simpler tactic, I have also significantly shortened the test file.

Johan Commelin (Sep 13 2022 at 09:24):

#16495

Johan Commelin (Sep 21 2022 at 06:56):

I merged master and fixed conflicts.

Johan Commelin (Sep 21 2022 at 06:59):

However, I must say that there is something going on with the generalizing clause that I don't understand completely.

  • Sometimes the tactic fails in mysterious ways if the generalizing clause is not present (the error suggests that the final exact in the source of the tactic is failing), and adding a generalizes x y solves the problem.
  • In other cases, I've seen a generalizing x y clause, and the tactic state would look all happy, but the kernel would reject the proof. Removing the generalizing clause solved the problem.

I've not been able to minimize.

Moritz Doll (Feb 07 2023 at 07:48):

I am in need of the wlog tactic for !4#2131. Is anyone working on porting it or is there a simple shortcut?

Moritz Doll (Feb 07 2023 at 07:50):

Also mathport goes a bit crazy on wlog:

trace
--"./././Mathport/Syntax/Translate/Tactic/Builtin.lean:75:38: in wlog #[[ident hle], [\":\", expr «expr ≤ »(u, v)], [\"generalizing\", ident u, ident v], []]: ./././Mathport/Syntax/Translate/Basic.lean:349:22: unsupported: too many args"

Ruben Van de Velde (Feb 07 2023 at 08:06):

Moritz Doll said:

Also mathport goes a bit crazy on wlog:

trace
--"./././Mathport/Syntax/Translate/Tactic/Builtin.lean:75:38: in wlog #[[ident hle], [\":\", expr «expr ≤ »(u, v)], [\"generalizing\", ident u, ident v], []]: ./././Mathport/Syntax/Translate/Basic.lean:349:22: unsupported: too many args"

@Mario Carneiro is that a mathport bug?

Johan Commelin (Feb 07 2023 at 08:07):

@Moritz Doll Very recently the wlog tactic in mathlib 3 was simplified. By now it should be "easy" to port.

Lukas Miaskiwskyi (Feb 07 2023 at 08:09):

I've also gotten fairly far by replacing wlog with swap_var, though it's a bit annoying since wlog was smart enough to find out all the dependent terms that needed to be swapped, and with swap_var you need to pick everything out manually. So first use e.g. casesto deconstruct the situation into different cases, on_goal x => swap_var for all the variable replacements, and then all_goals for the rest of the proof. But it's finicky. Here is my example: https://github.com/leanprover-community/mathlib4/blob/9749733b8f63c15ef3c310cbe6133f1f20cfa73d/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean#L213

Lukas Miaskiwskyi (Feb 07 2023 at 08:09):

But if wlog is easy to port, that is certainly the more useful way to go :)

Thomas Murrills (Feb 07 2023 at 08:28):

I can start porting it tomorrow if no one is working on it already :)

Mario Carneiro (Feb 07 2023 at 08:35):

I just changed the syntax to match lean 3:

/- B -/ syntax (name := wlog) "wlog " ident " : " term
  (" generalizing" (ppSpace colGt ident)*)? (" with " ident)? : tactic

make sure you use this if you are working on it

Mario Carneiro (Feb 07 2023 at 08:39):

on this note, what should the syntax of lean 4 wlog be? It seems to have been quite significantly changed in the last update, I'm not really sure how the new bells and whistles map onto the old ones:

/- B -/ syntax (name := wlog) "wlog" (" (" &"discharger" " := " term ")")?
  (ppSpace (colGt ident))? (" : " term)? (" := " term)? (" using " (ident*),+)? : tactic

Mario Carneiro (Feb 07 2023 at 08:39):

I guess the generalizing argument corresponds to the old using arg, although there is no longer a list of lists?

Mario Carneiro (Feb 07 2023 at 08:40):

and the with H argument is new, or is it the := arg?

Johan Commelin (Feb 07 2023 at 08:40):

generalizing just means a revert before the actual wlog call.

Mario Carneiro (Feb 07 2023 at 08:41):

I noticed that generalizing * is supported and means the same as nothing?

Johan Commelin (Feb 07 2023 at 08:41):

/-- `wlog h : P` will add an assumption `h : P` to the main goal,
and add a side goal that requires showing that the case `h : ¬ P` can be reduced to the case
where `P` holds (typically by symmetry).

The side goal will be at the top of the stack. In this side goal, there will be two assumptions:
- `h : ¬ P`: the assumption that `P` does not hold
- `this`: which is the statement that in the old context `P` suffices to prove the goal.
  By default, the name `this` is used, but the idiom `with H` can be added to specify the name:
  `wlog h : P with H`.

Typically, it is useful to use the variant `wlog h : P generalizing x y`,
to revert certain parts of the context before creating the new goal.
In this way, the wlog-claim `this` can be applied to `x` and `y` in different orders
(exploiting symmetry, which is the typical use case).

By default, the entire context is reverted. -/

Johan Commelin (Feb 07 2023 at 08:42):

I think this should answer your questions

Mario Carneiro (Feb 07 2023 at 08:42):

I see this but it doesn't cover migration questions

Johan Commelin (Feb 07 2023 at 08:42):

I don't have a good name for the h and H in wlog h L P with H.

Mario Carneiro (Feb 07 2023 at 08:42):

you are presuming that I know what the old version did :)

Mario Carneiro (Feb 07 2023 at 08:43):

does the with arg map onto anything in the old version?

Johan Commelin (Feb 07 2023 at 08:48):

Not sure. Why is that relevant?

Johan Commelin (Feb 07 2023 at 08:50):

My understanding is that with H is a new feature. In the old version, H was always called this. But maybe I'm missing something.

Thomas Murrills (Feb 07 2023 at 10:01):

I made a PR with blank files; I'll start actually looking at it tomorrow. In the meantime, if anyone wants to write a test or two beforehand in test/wlog.lean, that would be very much appreciated—I'm new to the tactic and seeing a couple lean 4 examples (and having the tests at the ready) will probably help speed things along! :) !4#2144

Thomas Murrills (Feb 09 2023 at 09:07):

Ok, wlog should be usable now! !4#2144

Thomas Murrills (Feb 09 2023 at 09:09):

I'm not putting it out for review just yet because the code itself could use an organizational once-over, and I want to sleep. But the functionality should be there, so @Moritz Doll if you're eager to start porting with it, feel free merge the wlog branch—and of course let me know if you run into any bugs 🙃

Kevin Buzzard (Feb 09 2023 at 09:36):

Thank you Thomas!

Moritz Doll (Feb 09 2023 at 13:25):

that is great news, thanks Thomas. I will put that into my branch tomorrow and report any errors.

Arien Malec (Feb 09 2023 at 17:14):

I'm using this with !4#2080 and blocked on using

Arien Malec (Feb 09 2023 at 17:24):

Unless using in mathli3 is the same as generalizing?

Thomas Murrills (Feb 09 2023 at 18:38):

The syntax has just now changed to use generalizing and with both in mathlib4 and mathlib3, and the mathlib3 and 4 versions match up in functionality! I’m not sure which corresponds to which (since I’m not familiar with the old version) but it should be one of the two. 🙃

Moritz Doll (Feb 10 2023 at 05:34):

Error message time:
Code is at https://github.com/leanprover-community/mathlib4/blob/362a3511b6cfe1940ff86171f2c772b7533ed481/Mathlib/Topology/Algebra/Order/LeftRightLim.lean#L266
and the error is that wlog does not find variables that have been introduced in the rintro in the line before (unknown identifier 'u'), so I suspect that it is a WithMainContext issue.

Moritz Doll (Feb 10 2023 at 05:37):

in fact it is, I commit the fix to your PR

Moritz Doll (Feb 10 2023 at 05:44):

with that my PR is error free

Thomas Murrills (Feb 10 2023 at 05:51):

ah nice, good catch! I was so worried about inner withMainContexts causing problems I forgot about the main one... :upside_down:

Moritz Doll (Feb 10 2023 at 05:54):

I've added a test as well. It is a bit stupid, but that keeps the bugs out

Thomas Murrills (Feb 10 2023 at 06:02):

Nice! All tests are welcome, the stupider (= more minimal!) the better :) I still haven't given the code that once-over since I didn't have much time today, but I hope to do so tomorrow—I wouldn't be surprised if there's another surprise in there. (...Well, you know what I mean.) I plan to add a couple more tests as well.

Arien Malec (Feb 10 2023 at 18:48):

Is this the same issue that cases swap to lose this in !4#2043?

Thomas Murrills (Feb 10 2023 at 19:40):

the fix is live now if you want to merge wlog and see if it works; but if not lmk and I’ll take a look (is this an issue with wlog or swap?)

Arien Malec (Feb 10 2023 at 19:56):

I've re-merged to make sure I picked up the latest.

I don't understand well what wlog does, but after wlog at line 400, I get the tactic state:

n: 
c: Composition n
i₁i₂: Fin (length c)
h: i₁  i₂
this:  {i₁ i₂ : Fin (length c)},
  i₁  i₂ 
    i₁  i₂  _root_.Disjoint (Set.range (embedding c i₁).toEmbedding) (Set.range (embedding c i₂).toEmbedding)
h': ¬i₁  i₂
 _root_.Disjoint (Set.range (embedding c i₁).toEmbedding) (Set.range (embedding c i₂).toEmbedding)
n: 
c: Composition n
i₁i₂: Fin (length c)
h: i₁  i₂
h': i₁  i₂
 _root_.Disjoint (Set.range (embedding c i₁).toEmbedding) (Set.range (embedding c i₂).toEmbedding)

where the second goal is missing this (and I've tried to name via with to no avail).

Thomas Murrills (Feb 10 2023 at 22:24):

Weird, I'll take a look rn

Thomas Murrills (Feb 10 2023 at 22:44):

Oops, I didn't read the message closely. the second goal should not have this; only the first goal gets a this, because this is only used in the first goal to prove that we can reduce to the second goal.

Thomas Murrills (Feb 10 2023 at 22:48):

It seems this has to with this file coming from an outdated mathlib3 source (from before the recent mathlib3 change to wlog). The mathlib3 proof looks a little different now; I'll fix it.

Thomas Murrills (Feb 11 2023 at 10:15):

Oops, realizing I never implemented the other half of binderIdent (_).

What should this look like? mathlib3 doesn't allow _ in this position, so I'm guessing it's a new feature? Is it just that we should generate some name (presumably h here) and introduce it with .implicit binder info?

Mario Carneiro (Feb 11 2023 at 10:19):

_ should be allowed wherever an identifier is allowed (when declaring new bindings), and it does nothing except name the variable automatically with an inaccessible name

Thomas Murrills (Feb 11 2023 at 10:28):

and inaccessible = has BinderInfo.implicit?

Thomas Murrills (Feb 11 2023 at 10:58):

wait a minute...maybe that's a red herring. case detects if names are inaccessible by whether they have macro scopes

Mario Carneiro (Feb 11 2023 at 11:12):

why are you detecting if the name is inaccessible?

Mario Carneiro (Feb 11 2023 at 11:12):

intro1 will introduce an anonymous variable

Thomas Murrills (Feb 11 2023 at 11:14):

I'm not actually trying to detect inaccessible names, I'm just trying to figure out what it means for a name to be inaccessible

Mario Carneiro (Feb 11 2023 at 11:15):

the short version is "it is printed with a tombstone"

Thomas Murrills (Feb 11 2023 at 11:16):

but behind the scenes, literally all that's different is that the name contains a tombstone? surely there's more?

Mario Carneiro (Feb 11 2023 at 11:16):

it could mean that the name is shadowed, it has macro scopes, or it uses internal name components

Thomas Murrills (Feb 11 2023 at 11:16):

hmmmm okay

Mario Carneiro (Feb 11 2023 at 11:16):

the name doesn't literally have a tombstone in it

Thomas Murrills (Feb 11 2023 at 11:17):

I did see one function which appeared to check for just that, so it sounded plausible

Mario Carneiro (Feb 11 2023 at 11:17):

but the idea is that writing the literal name you see for the variable won't resolve to that variable

Thomas Murrills (Feb 11 2023 at 11:18):

right, that part (how they should work/affect things) makes sense

Thomas Murrills (Feb 11 2023 at 11:18):

hmm intro1 works for one part

Thomas Murrills (Feb 11 2023 at 11:18):

but the other is an introduction of a hypothesis from byCases

Mario Carneiro (Feb 11 2023 at 11:19):

the point being that it's sort of an emergent property, it's not a flag on the name

Thomas Murrills (Feb 11 2023 at 11:20):

oh interesting. so when it's greyed out in the tactic state, how does lean "tell" that it should do that? and is being greyed out actually connected to being inaccessible, or is that a coincidence? (is it perhaps just a reflection of the binderinfo?)

Mario Carneiro (Feb 11 2023 at 11:20):

I believe it just does a name lookup with the name of the ldecl and if you don't get the same ldecl back then it's inaccessible

Mario Carneiro (Feb 11 2023 at 11:21):

the binderinfo is mostly unrelated

Thomas Murrills (Feb 11 2023 at 11:21):

how could the result of the name lookup differ if we're using the name to look it up, so to speak?

Mario Carneiro (Feb 11 2023 at 11:22):

there is a binderinfo for variables that are even more hidden than inaccessible names, isImplementationDetail. These will not be shown at all in the tactic state and are not accessible to tactics like assumption

Thomas Murrills (Feb 11 2023 at 11:23):

is there any relation between implementation details and aux decls?

Mario Carneiro (Feb 11 2023 at 11:23):

if you have two variables named x in the state, let's say with FVarIds 1 and 2 respectively, then getFVarByUserName? `x will give you FVarId 2 and so FVarId 1 is inaccessible

Thomas Murrills (Feb 11 2023 at 11:24):

ah okay

Mario Carneiro (Feb 11 2023 at 11:24):

IIRC implementation detail replaced aux decl

Mario Carneiro (Feb 11 2023 at 11:24):

that's not true, they are both there and serve similar functions

Mario Carneiro (Feb 11 2023 at 11:24):

I think they can probably be merged

Mario Carneiro (Feb 11 2023 at 11:26):

aux decls act more like global declarations than local variables for name resolution purposes

Thomas Murrills (Feb 11 2023 at 11:27):

I see, I just looked up the code and saw that there are default decls, aux decls, and implementation detail decls, though apparently isImplementationDetail means "not a .default decl"

Thomas Murrills (Feb 11 2023 at 11:29):

so anyway hmm. I need to make this fvar introduced by byCases into an inaccessible name

Thomas Murrills (Feb 11 2023 at 11:29):

or wait. do I

Mario Carneiro (Feb 11 2023 at 11:29):

you don't need to do anything special for that

Mario Carneiro (Feb 11 2023 at 11:29):

it already is unless you gave it a name explicitly

Thomas Murrills (Feb 11 2023 at 11:29):

because byCases doesn't, so maybe I shouldn't either

Thomas Murrills (Feb 11 2023 at 11:31):

byCases actually seems to use an explicit name h when a name is not given

Thomas Murrills (Feb 11 2023 at 11:31):

instead of an inaccessible one

Mario Carneiro (Feb 11 2023 at 11:32):

pass `_ for the name and an inaccessible name will be generated

Thomas Murrills (Feb 11 2023 at 11:35):

from a design point of view is that the right thing to do? if this is essentially the result of a by_cases tactic, should it be named accordingly?

Mario Carneiro (Feb 11 2023 at 11:36):

if you pass _ then it should not be named h (it can be named hygienic h if you like)

Mario Carneiro (Feb 11 2023 at 11:37):

if you pass nothing then it can maybe be named h (although that kind of design is being deprecated in lean 4)

Thomas Murrills (Feb 11 2023 at 11:37):

ah i see. irrelevant here anyway since the binderIdent is not optional for wlog

Thomas Murrills (Feb 11 2023 at 11:37):

so that decides that

Thomas Murrills (Feb 11 2023 at 11:43):

ok, fixed! :)

Thomas Murrills (Feb 11 2023 at 11:47):

(ok, now: fixed. long line snuck in.)

Thomas Murrills (Feb 11 2023 at 11:55):

I'm guessing that, in general, implementation details have no business being reverted, right?

Thomas Murrills (Feb 11 2023 at 11:55):

Or is that just an aux decls thing?

Thomas Murrills (Feb 11 2023 at 11:56):

wait, when you said "not visible in the tactic state"—do implDecls even appear when I retrieve a goal's local context?

Mario Carneiro (Feb 11 2023 at 11:59):

they do

Mario Carneiro (Feb 11 2023 at 12:00):

you should use isImplementationDetail when looping over the local context to skip those variables

Mario Carneiro (Feb 11 2023 at 12:01):

you should pretend that implementation detail variables don't exist at all for the purpose of tactic logic

Thomas Murrills (Feb 11 2023 at 12:02):

Makes sense, I was already filtering out aux decls

Mario Carneiro (Feb 11 2023 at 12:03):

that's why isImplementationDetail returns true for both implDetail and auxDecl

Thomas Murrills (Feb 11 2023 at 12:03):

Actually there is one thing here: revert has an option to clear aux decls instead of reverting them, but currently I just avoid feeding them to revert in the first place. Do you think that's alright? That's basically my last (known) issue with wlog.

Thomas Murrills (Feb 11 2023 at 12:05):

Oh wait. Clearing won't affect anything at the point I do it

Mario Carneiro (Feb 11 2023 at 12:05):

you should not use that optional parameter in revert

Thomas Murrills (Feb 11 2023 at 12:05):

I do it within withoutModifyingState, so whether I do or don't it won't matter—but cool, I will not :)

Mario Carneiro (Feb 11 2023 at 12:06):

if you let it do the default thing, it will fail if you pass it an aux decl

Thomas Murrills (Feb 11 2023 at 12:06):

right, that's what I found

Thomas Murrills (Feb 11 2023 at 12:06):

which is why I filter them out (well, now I filter all implementation details out)

Mario Carneiro (Feb 11 2023 at 12:06):

but you shouldn't do that anyway

Mario Carneiro (Feb 11 2023 at 12:07):

why are you going over the lctx in the first place?

Mario Carneiro (Feb 11 2023 at 12:08):

withoutModifyingState doesn't prevent failures from leaking out BTW

Thomas Murrills (Feb 11 2023 at 12:09):

yes, but presumably running .clear on an mvarid inside withModifyingState won't affect the outside world?

Mario Carneiro (Feb 11 2023 at 12:09):

only if it succeeds

Mario Carneiro (Feb 11 2023 at 12:10):

why would you use clear and then revert the state?

Thomas Murrills (Feb 11 2023 at 12:10):

Mario Carneiro said:

why are you going over the lctx in the first place?

same reason it's done in mathlib3: get the fvarids to revert, and revert them to construct the type of this (one of the reduction hypotheses)

Mario Carneiro (Feb 11 2023 at 12:10):

revert does that already

Thomas Murrills (Feb 11 2023 at 12:10):

Mario Carneiro said:

why would you use clear and then revert the state?

I wouldn't, but that's what revert does

Thomas Murrills (Feb 11 2023 at 12:15):

like here's what happened here: clearAuxDeclsInsteadOfReverting not only skips aux decls, it clears them. I currently just skip them (and filter them out before they get to revert.

I wondered "hmm, do I need to worry about some weird edge case where I would want them cleared? why is revert trying to clear them anyway? something I don't know about?"

then realized "wait, obviously: a successful clear operation doesn't matter, I'm doing it in withoutModifyingState" (a failed clear operation does matter, as you pointed out)

Mario Carneiro (Feb 11 2023 at 12:15):

it sounds like you don't need most of what revert does, actually, since you aren't making use of the mvar

Mario Carneiro (Feb 11 2023 at 12:15):

the main important logic is collectForwardDeps fvars preserveOrder

Thomas Murrills (Feb 11 2023 at 12:16):

that's true, is there an expression version that still lets me use the FVarIds?

Thomas Murrills (Feb 11 2023 at 12:16):

ah ok

Mario Carneiro (Feb 11 2023 at 12:18):

you also want to filter out the isImplementationDetail hyps from that

Mario Carneiro (Feb 11 2023 at 12:19):

Thomas Murrills said:

like here's what happened here: clearAuxDeclsInsteadOfReverting not only skips aux decls, it clears them. I currently just skip them (and filter them out before they get to revert.

It doesn't clear all aux decls, only the ones that would otherwise have been reverted

Mario Carneiro (Feb 11 2023 at 12:19):

the reason is that we want to pretend they don't exist, so they can't cause a failure of the tactic, nor can they show up in the implication of the new goal

Thomas Murrills (Feb 11 2023 at 12:21):

Mario Carneiro said:

you also want to filter out the isImplementationDetail hyps from that

you mean from the result...?

Mario Carneiro (Feb 11 2023 at 12:22):

yes

Mario Carneiro (Feb 11 2023 at 12:22):

forward deps means all hyps whose types depend on the variables that are about to be reverted

Mario Carneiro (Feb 11 2023 at 12:22):

those hyps all have to go, one way or another

Mario Carneiro (Feb 11 2023 at 12:22):

either they go into the implication or they are cleared

Mario Carneiro (Feb 11 2023 at 12:23):

(at least, in revert)

Mario Carneiro (Feb 11 2023 at 12:23):

in your case you are just constructing the implication without clearing stuff so you can just skip them

Thomas Murrills (Feb 11 2023 at 12:30):

ah, I see what you mean

Thomas Murrills (Feb 11 2023 at 12:38):

seems like the thing that actually makes the type after that is mkAuxMVarType, which handles a bunch of different cases, so I suppose I'll use that as well

Thomas Murrills (Feb 11 2023 at 20:04):

@Mario Carneiro, do you want to take a look at how this wound up (lines 77 - 82 WLOG.lean !4#2144), or shall I just go ahead and merge it? (It works fine in the tests and the mathlib4 file it's currently used in)

Thomas Murrills (Feb 11 2023 at 20:05):

(I was delegated merge privileges (exciting!), but it's changed since I was delegated those, so I thought I'd be prudent)

Thomas Murrills (Feb 11 2023 at 20:10):

(Or if anyone else wants to take a look at the refactor and give me the go ahead again, just in the interest of having everything be reviewed by someone who didn’t write it.)

Thomas Murrills (Feb 11 2023 at 21:07):

Actually there is something I don't understand about the code I used.

So, revert calls collectForwardDeps to get toRevertNew, then feeds the result to MetavarContext.revert. This uses a fresh cache (what does that do?) and calls elimMVar.

That actually calls collectForwardDeps again (the MkBinding version, which is what's lifted to the version used explicitly in revert), and has this note:

-- Note that `toRevert` only contains free variables at this point since it is the result of `getInScope`;
-- after `collectForwardDeps`, this may no longer be the case because it may include metavariables
-- whose local contexts depend on `toRevert` (i.e. "may dependencies")
let toRevert  collectForwardDeps mvarLCtx toRevert

mkAuxMVarType is then called on the resulting toRevert. But here's the thing I don't understand:

This toRevert (the one that "may include metavariables") is returned all the way up through to revert, where we then return toRevert.map Expr.fvarId!.

Thomas Murrills (Feb 11 2023 at 21:08):

So, I mean, the fact that revert uses Expr.fvarId! is a pretty good indication that we don't actually have to worry about those possible metavariables in this circumstance. But why don't we?

Thomas Murrills (Feb 13 2023 at 19:32):

Hmm, in the interest of not holding up the port, I’m just going to merge it—if there is a problem introduced by this refactor, it must only occur in some edge cases, and I’ll fix it at that point :)

Mario Carneiro (Feb 13 2023 at 19:34):

I'm in paper crunch time, so I don't have much time for reviewing. It looks plausible, we can pick up the pieces later

Thomas Murrills (Feb 13 2023 at 19:41):

Sounds good, good luck with the paper(s)! :)

Jon Eugster (Mar 28 2023 at 12:44):

I came across a bit of an unfortunate behaviour of wlog (sorry for the bit daft mwe):

import Mathlib.Tactic.WLOG
import Mathlib.Tactic.Tauto

-- some random global variables
variable {A B C : Prop}

example (h : A ) : A := by
    wlog a : A with h_wlog
    · have w := h_wlog h    -- fails
      -- don't know how to synthesize implicit argument
      -- @h_wlog A ?m.68 ?m.69
      -- It wants some values for `B` and `C`, even though they are not used at all in
      -- the theorem.
      -- have w := @h_wlog _ A A h    -- This works (or any other values for arg 2 and 3)
      apply w
      assumption
    · assumption

If there are too many variables in context that are not needed, then the first step of wlog still creates implicit holes for all of them (in h_wlog) and you have to explicitely plug in values for them. (see also !4#3153 )

Is there an easy fix for this? Or would I just have to delete all unnecessary variables?

Kevin Buzzard (Mar 28 2023 at 12:49):

aargh.

For some reason I still don't quite understand, Lean 4 finds it much harder to throw away variables which aren't being used in a proof. This is not the first time it's caused problems.

Floris van Doorn (Mar 28 2023 at 13:16):

A workaround is to use the clear tactic on all variables that you don't want, e.g. clear B C.

Thomas Murrills (Mar 28 2023 at 18:20):

Thanks for letting me know, I’ll take a look! :)

Thomas Murrills (Mar 28 2023 at 18:46):

Hmmm...this might be intended behavior for wlog, which is meant to revert the entire context by default. You can choose to only revert the parts of the context that depend on x y <etc> by using generalizing x y <etc>, e.g.

variable {A B C : Prop}

example (h : A) : A := by
    wlog a : A generalizing h with h_wlog
    · have w := h_wlog h -- ok
      apply w
      assumption
    · assumption

But maybe it shouldn't revert the entire context by default...open to any ideas!

Thomas Murrills (Mar 28 2023 at 18:49):

Though, maybe this is more a "how should variables work" problem than a wlog problem. If B and C weren't introduced into the context in the first place, we wouldn't need generalizing (note that generalizing A also works here).

Thomas Murrills (Mar 28 2023 at 19:03):

But, if we assume that's not going to change: is there any way a tactic can identify global variables not used in the theorem statement like B and C? If so I could simply remove those "probably irrelevant" ones from the default reverted context, if that would be a good idea. (Not sure.)

Thomas Murrills (Mar 28 2023 at 19:10):

@Jon Eugster what was the wlog issue in !4#3150 ?

Jon Eugster (Mar 28 2023 at 19:51):

Thanks for having a look @Thomas Murrills. I wouldn't know either what's the best default behaviour. And after all we're probably talking about wlog working in a bad context in the first place. I assume after the port some people will go and delete a lot of these variable (α β γ δ … : Type _) lines anyways.

#3150 does not have any issues with wlog, I mistook the apply @Nat.gcd.induction _ m n (which I had to write out) as an example of the case above, but that has nothing to do with wlog, my bad.

Scott Morrison (Apr 09 2023 at 08:33):

This has also arisen in !4#3152.


Last updated: Dec 20 2023 at 11:08 UTC