Zulip Chat Archive

Stream: mathlib4

Topic: exact_mod_cast and rationals


Eric Wieser (Nov 18 2024 at 17:26):

Is there a tactic that can solve these "trivial" goals, besides doing the sequence of manual rewrites?

import Mathlib

example {x : } (h : (x : ) = 1 + 2) : x = 1 + 2 := by
  exact_mod_cast h -- ok

example {x : } (h : (x : ) = 1 / 2) : x = 1 / 2 := by
  exact_mod_cast h -- fails

example {x : } (h : (x : ) = 1 + 2 / 3 + 0.5) : x = 1 + 2 / 3 + 0.5 := by
  exact_mod_cast h -- fails

Heather Macbeth (Nov 18 2024 at 18:10):

In both cases you can do rify; exact h. But it seems like it would be better to teach norm_cast to handle fractions and decimals.

Floris van Doorn (Nov 19 2024 at 18:32):

I thought norm_cast could already do this, because it can deal with fractions:

import Mathlib.Tactic

example {p q x : } (h : (x : ) = p / q) : x = p / q := by
  norm_cast at h

So it fails only on fractions with a number as both numerator and denominator.
And indeed:
src#Lean.Elab.Tactic.NormCast.derive
has a preprocessing step for dealing with natural number numerals, but not for rationals/decimals.
(and negative numbers are just negation applied to a natural number, so need no special preprocessing).

Eric Wieser (Nov 19 2024 at 23:48):

I think it is pretty tricky to teach it about rational numbers, since norm_cast is in core where Rat doesn't exist yet

Heather Macbeth (Nov 19 2024 at 23:56):

Maybe that's a reason to move norm_cast back to Batteries.

Eric Wieser (Nov 20 2024 at 00:00):

I was hoping that something like this might work, but it seems to just send norm_cast into an infinite loop:

import Mathlib

/-- Try to pull casts of numeric literals outside division -/
@[norm_cast move]
theorem Rat.cast_natCast_div_natCast [DivisionRing K] [CharZero K] (n d : ) : (n / d : K) =  (n / d : ) := by simp

example {x : } (h : (x : ) = 2 / 3) : x = 1 + 2 / 3 := by
  norm_cast at h

Eric Wieser (Nov 20 2024 at 00:03):

Oh, I can make this work!

Eric Wieser (Nov 20 2024 at 00:06):

@[norm_cast]
theorem Rat.cast_ofNat_div_ofNat [DivisionRing K] [CharZero K] (n d : ) [n.AtLeastTwo] [d.AtLeastTwo]:
    (no_index (OfNat.ofNat n) / no_index (OfNat.ofNat d) : ) =
      ((no_index (OfNat.ofNat n) : ) / (no_index (OfNat.ofNat d) : ) : K)
       := by simp

fixes the example with rationals

Heather Macbeth (Nov 20 2024 at 00:08):

Can you get OfScientific working too?

Eric Wieser (Nov 20 2024 at 00:08):

No, because the mechanism to make OfNat work is to insert a Nat.cast

Eric Wieser (Nov 20 2024 at 00:09):

So to make OfScientific work, we need to insert a Rat.cast (or NNRat.cast if we have a taste for worms)

Eric Wieser (Nov 20 2024 at 00:09):

Which of course core can't do

Eric Wieser (Nov 20 2024 at 00:11):

What core could do is handle Rat.cast_ofScientific specially, when it sees it has been tagged norm_cast

Eric Wieser (Nov 20 2024 at 00:24):

Allowing simprocs to be registered with norm_cast would probably work too


Last updated: May 02 2025 at 03:31 UTC