Zulip Chat Archive

Stream: new members

Topic: Is there a mathlib tactic for closing arithmetic goals?


Alexander Lucas (Aug 15 2023 at 04:56):

I have lots of goals like the following forall (i j k : Nat), i * j = i * (j - k) + k * i. I thought maybe norm_num would do it, but it seems to have no effect.

import Mathlib.Tactic.NormNum
theorem H {i j k : Nat} : i * j = i * (j - k) + k * i := by
  norm_num

The goal is the same after norm_num as it is before.
The ring tactic does change the goal a bit, but not in any especially helpful way as far as I can tell.

Hopefully I'm not missing something obvious. Thank you.

Alexander Lucas (Aug 15 2023 at 05:01):

I guess that example actually isn't true, since k > j means j - k < 0, which can't happen in Nats.

Moritz Doll (Aug 15 2023 at 05:11):

Alexander Lucas said:

I guess that example actually isn't true, since k > j means j - k < 0, which can't happen in Nats.

Subtraction a - b on natural numbers is defined as zero if b > a, so your claim is false. You want to use integers and then ring should prove your claim

Alexander Lucas (Aug 15 2023 at 05:17):

Thank you, yeah. Is it possible to do induction on integers though? Pick a base case n and induct for m > n?
Also, incidentally, what _is_ norm_num for? If you don't mind.

Moritz Doll (Aug 15 2023 at 05:19):

norm_num is for calculations with explicit numbers:

example : 4 + 1= 1 + 2*2 := by
  norm_num

Alexander Lucas (Aug 15 2023 at 05:20):

I see. Thanks.

Moritz Doll (Aug 15 2023 at 05:21):

(by calculation I mean normalizing)

Moritz Doll (Aug 15 2023 at 05:28):

The induction tactic works with integers, but then you have to prove your statement for the natural numbers and then for n-1 assuming n. In the natural number case you can do induction again and together with some artifical inserting of zeros you can shift the base case to any integer n.

Moritz Doll (Aug 15 2023 at 05:28):

But I have no idea whether there is something out of the box for that

Moritz Doll (Aug 15 2023 at 05:30):

without the shifting there is docs#Int.induction_on

Alexander Lucas (Aug 15 2023 at 05:34):

I appreciate it mate. I'll try to make that work.

Alexander Lucas (Aug 15 2023 at 07:44):

By looking in the file you pointed me to, I found the tactic Int.le_induction, which seems to do what I need. Here's an example using it.

def postage_ℤ : (n : )  (h : 4  n)   j k, n = 2 * j + 5 * k := by
  intro n H
  apply @Int.le_induction (fun x => (h : 4  x)   j k, x = 2 * j + 5 * k) 4
  . intro _
    exists 2, 0
  . intro z h₁ h₂
    match h₂ h₁ with
    | j', k', h₂ =>
      apply @Classical.byCases (k' = 0) <;> intro h₃ _
      . exists (j' - 2), 1
        rw [h₂, h₃]
        ring
      . exists (j' + 3), (k' - 1)
        rw [h₂]
        ring
  all_goals exact H

Maarten Derickx (Aug 15 2023 at 21:57):

The ring tactic works better in the integers then over the natural numbers when substraction is involved. Since in general (j - k) is not a natural number. Try the following:

import Mathlib

#eval 6 - 9
#eval (6: ) - 9

theorem H {i j k : } : i * j = i * (j - k) + k * i := by
  ring

Alexander Lucas (Aug 15 2023 at 22:05):

Thanks. I ended up coming to the same conclusion. I do have another related question. Say I have some arithmetic expression of naturals with a subexpression (j - k). Say I also have some H : k <= j. Since, under this assumption H, j - k is generally a natural number, is there a way to convey that fact to ring, directly or indirectly, such that the goal can still be closed without a bunch of manual rewriting?

Alex J. Best (Aug 15 2023 at 22:05):

tactic#zify

Alexander Lucas (Aug 15 2023 at 22:06):

Well damn, that was quick. Thanks!

Alex J. Best (Aug 15 2023 at 22:06):

This isn't exactly what you asked for, but zify [H], ring is what I would do in that situation :smile:


Last updated: Dec 20 2023 at 11:08 UTC