Zulip Chat Archive

Stream: new members

Topic: Tactic for simplification in division with many variables?


Tyler Josephson ⚛️ (Jan 29 2024 at 02:40):

One of my students needed this theorem to solve a bigger problem, and we found the last step of the calc block particularly cumbersome, mainly due to the order of operations and the challenge of moving terms around. How to do this in fewer lines?

import Mathlib.Tactic

theorem helper {a b c d e : }
(hb : b  0) (h1 : a ^ 2 * b = c * d * b / e * 2) : a ^ 2 = c * d / e * 2
:= by
  calc
    a ^ 2 = a ^ 2 * b / b := by rw[mul_div_cancel]; apply hb
    _ = (c * d * b / e * 2) / b := by rw[h1]
    _ = c * d / e * 2 := by ring; rw[mul_comm c, mul_assoc (d * c), mul_comm b,  mul_assoc, mul_assoc (d * c * e⁻¹), mul_inv_cancel]; ring; apply hb

Is there a tactic that can automatically cancel equal terms in the numerator and denominator, no matter where in the numerator and denominator may appear, provided the term being canceled is nonzero?

Heather Macbeth (Jan 29 2024 at 02:52):

Quick solution, not using your scaffolding:

theorem helper {a b c d e : } (hb : b  0) (h1 : a ^ 2 * b = c * d * b / e * 2) :
    a ^ 2 = c * d / e * 2 := by
  apply mul_left_cancel₀ hb
  linear_combination h1

Heather Macbeth (Jan 29 2024 at 02:59):

Minimizing the last of your steps, it seems that field_simp is not doing what one would hope there:

import Mathlib.Tactic

example {a b c d e : } (hb: b  0) :
    c * d * b / e * 2 / b = c * d / e * 2 := by
  field_simp

leaves the goal

⊢ c * d * b * 2 / (e * b) = c * d * 2 / e

where you'd hope that it would use hb to leave

⊢ c * d * 2 / e = c * d * 2 / e

instead. This might be a bug in field_simp. Or it might be just an expected consequence of the somewhat simplistic implementation of field_simp (literally, it's a wrapper around simp ...), fixable by giving a more principled implementation.

Tyler Josephson ⚛️ (Jan 29 2024 at 14:44):

We'd love a more powerful field_simp - is anyone with know-how interested in this? In our science derivations, we often have to juggle expressions like these.

Martin Dvořák (Jan 29 2024 at 14:46):

My students also complain about insufficient automation when working with fractions. I guess these tactics aren't easy to develop. I don't know about anyone working on better field_simp now.

Alex J. Best (Jan 29 2024 at 15:38):

We could add some field_simp lemmas like so

import Mathlib.Tactic

variable {K : Type*} [Field K]
@[field_simps]
theorem div_mul_eq_iff {a b c d : K} (hb : b  0) : a / (b * d) = c  a / d = c * b := by
  by_cases hd : d = 0; simp [hd, hb]; tauto
  have : b * d  0 := by simp [hb, hd]
  field_simp [mul_assoc]

@[field_simps]
theorem div_mul_eq_iff' {a b c d : K} (hd : d  0) : a / (b * d) = c  a / b = c * d := by
  by_cases hb : b = 0; simp [hd, hb]; tauto
  have : b * d  0 := by simp [hb, hd]
  field_simp
  ring_nf

example {a b c d e : } (hb: b  0) :
    c * d * b / e * 2 / b = c * d / e * 2 := by
  field_simp

Alex J. Best (Jan 29 2024 at 15:39):

There will of course be many (too many!) variations, but perhaps these ones are common enough to be useful.


Last updated: May 02 2025 at 03:31 UTC