Zulip Chat Archive
Stream: general
Topic: Working with `Even` and `Odd`
Matthew Pocock (Sep 07 2023 at 20:01):
I've been struggling to work with the Even
and Odd
rules. They often seem to behave as if they are opaque to other tactics, and Odd n
keeps getting simplified to ¬Even n
when I'm not looking, preventing simplification rules defined in terms of Odd n
from working.
⊢ ¬Even n → Even (if Even n then n / 2 else 3 * n + 1)
So for example, this target won't simplify out the if/else case. To get simp to start to work on it, I have to do quite a lot of work by hand to unpack the even
s, by which time something have gotten themselves messy. It should be obvious that this can be simpified as-is to 3 * n + 1
.
But it's worse than that. What I actually wanted to work with was:
⊢ Odd n → Even (if Even n then n / 2 else 3 * n + 1)
I actually need the witness for Odd n
to provide the witness to the outer Even _
. But the simplifier eagerly flips it, loosing the witness in the process.
Am I doing things wrongly? It feels like I'm fighting the library which is usually a sign that I'm not using it as intended.
Yaël Dillies (Sep 07 2023 at 20:02):
Nat.odd_iff_not_even
. Let me fix that.
Kevin Buzzard (Sep 07 2023 at 20:17):
In this particular case you probably do want "not even n" because you can then intro h; rw [if_neg h]
to simplify the if/then.
Matthew Pocock (Sep 07 2023 at 20:22):
Kevin Buzzard said:
In this particular case you probably do want "not even n" because you can then
intro h; rw [if_neg h]
to simplify the if/then.
OK, but I also need the outer Odd, as I need to get its existential -- I need that variable to unify at the other end to prove the rhs Even constraint.
Kevin Buzzard (Sep 07 2023 at 20:31):
Maybe post a #mwe to better explain your question? This is by far the most efficient way to ask a Lean question.
Matthew Pocock (Sep 07 2023 at 21:25):
This was the code I ended up with in the end. I'm not particularly happy with it, particularly the step where I do some gymnastics to reduce the if statement.
import Mathlib.Tactic
variable (n : Nat)
def collatz := if Even n then n / 2 else 3 * n + 1
theorem collatz_odd_to_even : Odd n -> Even (collatz n) := by
intro hon
rw [collatz]
simp [Iff.mp Nat.odd_iff_not_even hon] -- reduce the if statement
obtain ⟨ x, rfl ⟩ := hon
rw [Even]
use 3 * x + 2
simp [←Nat.two_mul, mul_add, ←mul_assoc]
Kevin Buzzard (Sep 07 2023 at 21:30):
If you abuse definitional equality and use ring
you can get your version down to this:
theorem collatz_odd_to_even : Odd n -> Even (collatz n) := by
intro hon
simp only [collatz, Iff.mp Nat.odd_iff_not_even hon, ite_false] -- reduce the if statement
obtain ⟨ x, rfl ⟩ := hon
use 3 * x + 2
ring
Kevin Buzzard (Sep 07 2023 at 21:37):
Here's a version which avoids the Iff.mp
thing:
theorem collatz_odd_to_even : Odd n -> Even (collatz n) := by
intro hon
have h : ¬ Even n := by simpa using hon
rw [collatz, if_neg h]
obtain ⟨ x, rfl ⟩ := hon
use 3 * x + 2
ring
Matthew Pocock (Sep 07 2023 at 21:53):
Thanks! The ring
tactic is a godsend here. I wish I'd known about it sooner.
Eric Rodriguez (Sep 07 2023 at 22:02):
there's a parity_simps
simp-set somewhere
Bhavik Mehta (Sep 07 2023 at 22:32):
Yaël Dillies said:
Nat.odd_iff_not_even
. Let me fix that.
Yeah this being simp
has annoyed me very often, I don't think it's particularly good as a simp lemma
Matthew Pocock (Sep 10 2023 at 14:01):
Can I enable parity_simps
locally within a file? I tried attribute [local simp] parity_simps
but it didn't seem to like that. Also, can I disable Nat.odd_iff_not_even
from being considered as a simp within my file? I can put parity_simps
within a simp, but I can't see how to just enable it everywhere.
Alex J. Best (Sep 10 2023 at 14:04):
As far as a I know that's not possible directly at the moment, you could easily define a macro that does simp [parity_simps]
though, but making a version of that that's more flexible might be more trouble than it's worth depending how long your file is.
Kevin Buzzard (Sep 10 2023 at 14:04):
parity_simps
is a simp set, not one lemma, so I doubt attribute [local simp] parity_simps
will work. For removing simp does attribute [-simp] Nat.odd_iff_not_even
work? A more aggressive approach would be to PR the change removing simp
from that lemma becasue people have complained before about it being in the simp set.
Kyle Miller (Sep 10 2023 at 14:04):
I'm not aware of it, but it seems like it'd be a reasonable command to add to mathlib (where you take every lemma in a simp set and give it the simp
attribute locally). Feel free to create a mathlib4 issue describing what you want and what problems this solves.
Kyle Miller (Sep 10 2023 at 14:06):
While on the face of it it doesn't seem that saving the extra keystrokes in simp [parity_simps]
is worth it, there's automation that calls simp
so this command would enable that automation to use parity_simps
lemmas locally.
Matthew Pocock (Sep 10 2023 at 14:20):
https://github.com/leanprover-community/mathlib4/issues/7082
https://github.com/leanprover-community/mathlib4/issues/7083
Last updated: Dec 20 2023 at 11:08 UTC