Zulip Chat Archive

Stream: general

Topic: A tactic I'd find useful


Bhavik Mehta (Jan 10 2024 at 18:05):

At the moment, field_simp is great for multiplying out equalities in a field. It would be nice if we have something which could also multiply out denominators in an ordered field, potentially using positivity to know what's positive (or negative). Here's the example that made me think of this:

lemma test_case {E A B : } {K : } (hK : 0 < K) (hE : K⁻¹ * (A ^ 2 * B)  E)
    (hA : 0 < A) (hB : 0 < B) :
    A / (Real.sqrt 2 * K)  Real.sqrt 2⁻¹ * (E / (A * B)) := by
  rw [inv_mul_le_iff hK] at hE
  rw [mul_div_assoc', div_le_div_iff, mul_assoc, sq]
  rotate_left
  · positivity
  · positivity
  refine hE.trans_eq ?_
  field_simp
  ring

The proof is pretty ad-hoc but really this feels like it should be simpler... nlinarith can't do it either, even knowing positivity for A,B as reals.

Yaël Dillies (Jan 10 2024 at 19:42):

@Heather Macbeth has this for teaching IIRC

Bolton Bailey (Jan 10 2024 at 20:17):

Here is a proof which is much more complicated, but has the virtue of requiring only a single tactic call.

import Mathlib

lemma div_eq_iff' [Field F] (a b c : F) :
    (a / b) = c  (b = 0  c = 0)  (¬ b = 0  a = b * c) := by
  by_cases h : b = 0
  · simp_all
    exact eq_comm
  · simp_all
    constructor
    · intro h'
      rw [ h']
      exact (mul_div_cancel' a h).symm
    · intro h'
      rw [h']
      exact mul_div_cancel_left c h

lemma div_le_iff'' [LinearOrderedField F] (a b c : F) :
    (a / b)  c  (b = 0  0  c)  (0 < b  a  b * c)  (b < 0  b * c  a) := by
  by_cases h : b = 0
  · simp_all
  · simp_all
    cases' lt_or_gt_of_ne h with h' h'
    · have h'' : ¬ 0 < b := by
        exact lt_asymm h'
      simp [h'', h']
      rw [div_le_iff_of_neg h']
      rw [mul_comm]
    · have h'' : ¬ b < 0 := by
        exact lt_asymm h'
      simp [h'', h']
      rw [div_le_iff h']
      rw [mul_comm]

lemma le_div_iff'' [LinearOrderedField F] (a b c : F) :
    a  b / c  (c = 0  a  0)  (0 < c  a * c  b)  (c < 0  b  a * c) := by
  by_cases h : c = 0
  · simp_all
  · simp_all
    cases' lt_or_gt_of_ne h with h' h'
    · have h'' : ¬ 0 < c := by
        exact lt_asymm h'
      simp [h'', h']
      rw [le_div_iff_of_neg h']
    · have h'' : ¬ c < 0 := by
        exact lt_asymm h'
      simp [h'', h']
      rw [le_div_iff h']

example [LinearOrderedField F] (a b c : F) : (a / b) * c = (a * c) / b := by
  exact div_mul_eq_mul_div a b c

lemma mul_lt_zero_iff''' [LinearOrderedField F] (a b : F) :
    a * b < 0  (a < 0  0 < b)  (0 < a  b < 0)  := by
  sorry


lemma test_case {E A B : } {K : } (hK : 0 < K) (hE : K⁻¹ * (A ^ 2 * B)  E)
    (hA : 0 < A) (hB : 0 < B) :
    A / (Real.sqrt 2 * K)  Real.sqrt 2⁻¹ * (E / (A * B)) := by
  simpa [-one_div, mul_div_assoc, div_mul_eq_mul_div, div_le_iff'', le_div_iff'', mul_lt_zero_iff''',
    Nat.cast_pos.mpr, Nat.pos_iff_ne_zero.mp, ne_of_gt, lt_asymm, inv_eq_one_div, mul_assoc, pow_two,
    mul_comm _ (Real.sqrt _), mul_left_comm _ (Real.sqrt _),
    hA, hB, hK] using hE

Heather Macbeth (Jan 10 2024 at 20:34):

Yaël Dillies said:

Heather Macbeth has this for teaching IIRC

No, I don't. I faked this tactic (i.e. gave a hack implementation) once or twice for talks (e.g. here) and Terry also proposed it at some point. I think this would be a great tactic, but as you can see at that thread, it seems to require a more principled implementation than field_simp's current implementation.


Last updated: May 02 2025 at 03:31 UTC