Zulip Chat Archive

Stream: Is there code for X?

Topic: weaker wlog


Tristan Figueroa-Reid (Jun 14 2025 at 20:16):

I use wlog as a general way to have guard statements in my proofs for cases that I don't care about - e.g. if I had 4 trivial cases, I wouldn't want to nest a by_cases statement or try to construct some hypothesis that I can plug into rcases. Is there some kind of wlog-like tactic that mimics this sort of style,?

Example:

unless h : a = b
· sorry
unless h : c = d
· sorry
-- The rest of the proof which holds when a ≠ b ∧ c ≠ d

Eric Wieser (Jun 14 2025 at 20:18):

Can you make a mwe?

Eric Wieser (Jun 14 2025 at 20:19):

(eg, a proof using by_cases you want a different spelling of)

Eric Wieser (Jun 14 2025 at 20:20):

Is the wlog here along the lines of what you want?

Tristan Figueroa-Reid (Jun 14 2025 at 20:20):

Eric Wieser said:

Is the wlog here along the lines of what you want?

That is the use case that I was thinking of :+1:

Tristan Figueroa-Reid (Jun 14 2025 at 20:46):

import Mathlib.Tactic

theorem div_le_self₁ (n k : Nat) : n / k  n := by
  induction n using Nat.strongRecOn with
  | ind n ih =>
    rw [Nat.div_eq]
    by_cases h : (0 < k  k  n)
    · suffices (n - k) / k + 1  n by simp [h, this]
      have hK, hKN := h
      have hSub : n - k < n := Nat.sub_lt (Nat.lt_of_lt_of_le hK hKN) hK
      have : (n - k) / k  n - k := ih (n - k) hSub
      exact Nat.succ_le_of_lt (Nat.lt_of_le_of_lt this hSub)
    · simp [h]

theorem div_le_self₂ (n k : Nat) : n / k  n := by
  induction n using Nat.strongRecOn with
  | ind n ih =>
    rw [Nat.div_eq]
    wlog h : (0 < k  k  n)
    · simp [h]
    suffices (n - k) / k + 1  n by simp [h, this]
    have hK, hKN := h
    have hSub : n - k < n := Nat.sub_lt (Nat.lt_of_lt_of_le hK hKN) hK
    have : (n - k) / k  n - k := ih (n - k) hSub
    exact Nat.succ_le_of_lt (Nat.lt_of_le_of_lt this hSub)

Tristan Figueroa-Reid (Jun 14 2025 at 20:48):

[Not exactly an MRE, but more of a motivating example]

Take this proof of div_le_self with by_cases vs with wlog - the latter reads more like a paper-and-pen proof. It would be nice if we had a version of wlog which didn't carry the symmetric hypothesis and was named unless.

Eric Wieser (Jun 14 2025 at 20:52):

I think unless in do notation is also missing the h: notation, maybe both should be added at once

Jz Pan (Jun 15 2025 at 06:38):

I think your unless h : a = b is just by_cases h : a = b; swap

Tristan Figueroa-Reid (Jun 15 2025 at 06:41):

I haven't seen anyone use swap after by_cases to replicate this but it is essentially just that.

I have seen the wlog pattern frequently like in the PR Eric Wieser mentioned above - though it does make sense not to add this tactic since it is a synonymous tactic to by_cases ...; swap or wlog ... ; clear this.

Tristan Figueroa-Reid (Jun 15 2025 at 06:44):

Though, are these sort of 'synonymous' tactics accepted? I've been using wlog to fill in this role for quite some time now, but I recently made a PR for the Seymour project that used this three times, and using wlog here is abuse of notation, but by_cases causes me to completely break the flow of the proof unless I consistently use the aforementioned swap.

Jz Pan (Jun 15 2025 at 06:47):

Tristan Figueroa-Reid said:

I haven't seen anyone use swap after by_cases to replicate this but it is essentially just that.

There are several use cases in mathlib: https://github.com/leanprover-community/mathlib4/blob/9b0c6a877559b4bb45860affaeafb705cee085aa/Mathlib/Order/Filter/ENNReal.lean#L136 https://github.com/leanprover-community/mathlib4/blob/9b0c6a877559b4bb45860affaeafb705cee085aa/Mathlib/RingTheory/RingHom/Integral.lean#L59 https://github.com/leanprover-community/mathlib4/blob/9b0c6a877559b4bb45860affaeafb705cee085aa/Mathlib/MeasureTheory/Function/UnifTight.lean#L253 https://github.com/leanprover-community/mathlib4/blob/9b0c6a877559b4bb45860affaeafb705cee085aa/Mathlib/Algebra/Homology/Embedding/Connect.lean#L86 and so on.

Tristan Figueroa-Reid (Jun 15 2025 at 06:56):

Interesting! Yet, we do also have plenty of examples of wlog being used without references to this! (I did check to make sure that these worked after clear this)

https://github.com/leanprover-community/mathlib4/blob/50e49dc2e9c35748e2313071052bdb6dd16a6fe5/Mathlib/Data/Matroid/Circuit.lean#L128 https://github.com/leanprover-community/mathlib4/blob/50e49dc2e9c35748e2313071052bdb6dd16a6fe5/Archive/Wiedijk100Theorems/BuffonsNeedle.lean#L325 https://github.com/leanprover-community/mathlib4/blob/50e49dc2e9c35748e2313071052bdb6dd16a6fe5/Mathlib/Order/KrullDimension.lean#L141 https://github.com/leanprover-community/mathlib4/blob/50e49dc2e9c35748e2313071052bdb6dd16a6fe5/Mathlib/Topology/Separation/Regular.lean#L256

Tristan Figueroa-Reid (Jun 15 2025 at 06:57):

Actually, even if synonymous tactics are discouraged, it could be worthwhile to add a linter looking for wlog without usages of the generated symmetric hypothesis and suggest a by_cases ...; swap.

Ruben Van de Velde (Jun 15 2025 at 09:26):

There's also by_cases; case neg =>

Eric Wieser (Jun 15 2025 at 10:56):

It sounds like the PR I linked should not be using wlog after all?

Johan Commelin (Jun 16 2025 at 08:36):

Tristan Figueroa-Reid said:

Though, are these sort of 'synonymous' tactics accepted? I've been using wlog to fill in this role for quite some time now, but I recently made a PR for the Seymour project that used this three times, and using wlog here is abuse of notation, but by_cases causes me to completely break the flow of the proof unless I consistently use the aforementioned swap.

I think that such synonymous tactics can improve the readability of the proof, and the intent of the author.
In this case, it sounds like the tactic can be implemented as a rather easy tactic macro, with a well-defined spec.
I would be open to adding it.

Yaël Dillies (Jun 16 2025 at 08:39):

Sorry, but I would like to stop you right here: We had been talking about making by_cases run push_neg, which here would allow you to do

by_cases hab : a  b
· sorry -- `hab : a ≠ b` is in context
by_cases hcd : c  d
· sorry -- `hab : a = b` and `hcd : c ≠ d` are in context
-- `hab : a = b` and `hcd : c = d` are in context

Yaël Dillies (Jun 16 2025 at 08:39):

IMO this is a much better solution than introducing yet another tactic

Jz Pan (Jun 16 2025 at 10:42):

Yaël Dillies said:

We had been talking about making by_cases run push_neg

Maybe we should introduce by_cases! to make by_cases backward compatible.

Yaël Dillies (Jun 16 2025 at 11:12):

We really should avoid introducing new tactics/variants thereof when the existing tactics can be modified. Does anyone really rely on getting hP : ¬ ¬ P in the second branch when doing by_cases hP : ¬ P?

Jz Pan (Jun 16 2025 at 11:13):

But contrapose and by_contra tactics normally do not push_neg, only their ! version do.

So IMHO this should be the same for by_cases.

Ruben Van de Velde (Jun 16 2025 at 11:13):

Probably most code that does that, but will be easy to fix

Ruben Van de Velde (Jun 16 2025 at 11:13):

Though I don't mind either way

Yaël Dillies (Jun 16 2025 at 11:13):

Jz Pan said:

But contrapose and by_contra tactics normally do not push_neg, only their ! version do.

Yes, I believe that should be fixed too

Ruben Van de Velde (Jun 16 2025 at 11:47):

I guess there's a stronger argument to do all three at the same time

Mario Carneiro (Jun 19 2025 at 19:55):

I would prefer if push_neg is called explicitly or via !. I don't want to see if running push_neg

Yaël Dillies (Jun 19 2025 at 20:00):

Tactic-mode if or term-mode if? I personally am happy to see both stay the way they are: if is computer-science, by_cases is mathematics, so the difference in behavior seems acceptable to me

Mario Carneiro (Jun 19 2025 at 20:03):

if is syntax for by_cases

Mario Carneiro (Jun 19 2025 at 20:04):

I don't think cs vs mathematics is the right way to differentiate push_neg vs not

Mario Carneiro (Jun 19 2025 at 20:04):

it has to do with whether you want to control the goal state or are just bashing away

Yaël Dillies (Jun 19 2025 at 20:05):

... whether the goal is Type- or Prop-valued?

Mario Carneiro (Jun 19 2025 at 20:05):

as well as whether you are wanting to hide details for e.g. a tutorial

Mario Carneiro (Jun 19 2025 at 20:05):

no, the goal is unrelated

Mario Carneiro (Jun 19 2025 at 20:05):

this is about rewriting the condition

Tristan Figueroa-Reid (Jun 20 2025 at 03:56):

(I forgot to check in with this thread) Thanks for this! I'll update the linting thread to reflect the conversation here :+1:


Last updated: Dec 20 2025 at 21:32 UTC