Zulip Chat Archive

Stream: new members

Topic: Tips on calculations with Reals


Adomas Baliuka (Jan 14 2024 at 06:04):

How would one approach the following? Third grade math, took me forever to do and it's insanely ugly. After getting it to type-check, I tried for 10 more minutes to "golf" it but I regularly break it and have to backtrack...

I guess the main problem is that the tactics don't realize that log 2 and 1 - x are non-zero?

import Mathlib
open Real

lemma move_factor_one_minus {x : } (h : 1  x): (1-x) * (1 /(1-x)) = 1 := by
    field_simp
    apply div_self
    exact sub_ne_zero.mpr h

lemma move_factor' {x y z : } (hy : 0  y) (hz : z  0) : (x / y) * (1 / z) = x / (y * z) := by
    field_simp

lemma zero_ne_mul_of_ne_zero  {x y : } (hx : x  0) (hy : y  0) : 0  x * y := by
    simp_all only [ne_eq, zero_eq_mul, or_self, not_false_eq_true]

lemma factor_out_denom (a b x : ) (hx : x  0) : a / x - b/x = (a - b) / x := by field_simp

lemma the_calculation {x : } (hx : x  0) (h2 : x  1) :
    -1 / (1 - x) / log 2 - x⁻¹ / log 2 = -1 / (x * (1 - x) * log 2) :=
  have zero_ne_one_neg_mul_log2 : 0  (1 - x) * log 2 := by
    exact zero_ne_mul_of_ne_zero (sub_ne_zero.mpr h2.symm) (by norm_num)
  calc
    _ = -(1 / ((1 - x) * log 2) * (x / x)) - 1 / (x * log 2) := by field_simp
    _ = -(1 / ((1 - x) * log 2) * x * (1 / x)) - 1 / (x * log 2) := by
      simp_all only [ne_eq,log_eq_zero, one_div,mul_inv_rev,not_false_eq_true,div_self,
      mul_one,mul_inv_cancel_right₀]
    _ = -(1 / ((1 - x) * log 2) * x * (1 / x)) - ((1-x) * (1 /(1-x))) / (x * log 2) := by
      rw [move_factor_one_minus h2.symm]
    _ = -(x  / ((1 - x) * log 2) * (1 / x)) - (1-x) / (x * log 2) / (1-x) := by ring
    _ = -(x  / (((1 - x) * log 2 * x) )) - (1-x) / (x * log 2) / (1-x) := by
        rw [move_factor' zero_ne_one_neg_mul_log2 hx]
    _ = -(x  / ((1 - x) * log 2 * x) ) - (1-x) / (x * log 2 * (1-x)) := by field_simp
    _ = -x / ((1 - x) * log 2 * x) - (1-x) / ((1 - x) * log 2 * x) := by ring
    _ = (-x - (1-x)) / ((1 - x) * log 2 * x) := by
      have : (1 - x) * log 2 * x  0 := by
        exact mul_ne_zero zero_ne_one_neg_mul_log2.symm hx
      rw [factor_out_denom (-x) (1-x) _ this]
    _ = -1 / (x * (1 - x) * log 2) := by ring

Andrew Yang (Jan 14 2024 at 06:16):

lemma the_calculation {x : } (hx : x  0) (h2 : x  1) :
    -1 / (1 - x) / log 2 - x⁻¹ / log 2 = -1 / (x * (1 - x) * log 2) := by
  apply neg_injective
  simp only [neg_div, neg_sub, sub_neg_eq_add, neg_neg,  one_div]
  rw [ add_div,  div_div]
  rw [div_add_div]
  · simp
  · exact hx
  · exact sub_ne_zero.mpr h2.symm

Adomas Baliuka (Jan 14 2024 at 06:16):

Wow... How did you do it this fast? Any tricks? How did you decide to start with neg_injective?

Andrew Yang (Jan 14 2024 at 06:27):

First of all about your helper lemmas:
Usually you can guess what name a lemma should be based on its signature.
For example (a - b)/x = a/x - b/x (your factor_out_denom) would be called docs#sub_div (and to rewrite in the other direction you do ← sub_neg). by exact? (or loogle) would help you find it too.
And x * y ≠ 0 would be docs#mul_ne_zero, and a/b + c/d = (a*d+b*c)/(b*d) would be docs#div_add_div etc.
Now, the main part of the proof is 1/(1-x) + 1/x = 1/(x*(1-x), so I first got rid of the negation
via apply neg_injective and the next simp line.
rw [← add_div, ← div_div] then makes both sides of the form ?_ / log 2, and rw [div_add_div] adds the two fractions together. Then just trust that simp can take care of the rest.
(I ungolfed the proof a bit to retro fit this explanation)

Andrew Yang (Jan 14 2024 at 06:34):

Or maybe this calc proof is more readable?

lemma the_calculation {x : } (hx : x  0) (h2 : x  1) :
    -1 / (1 - x) / log 2 - x⁻¹ / log 2 = -1 / (x * (1 - x) * log 2) :=
  calc
    _ = -(1/x + 1/(1-x)) / log 2 := by
      simp [neg_div, add_div, sub_eq_add_neg]
    _ = -(1 / (x * (1 - x))) / log 2 := by
      congr
      rw [div_add_div]
      · simp
      · exact hx
      · exact sub_ne_zero.mpr h2.symm
    _ = -1 / (x * (1 - x) * log 2) := by
      simp only [div_div, neg_div]

Yaël Dillies (Jan 14 2024 at 09:27):

You mean docs#sub_div, not sub_neg, Andrew.

David Loeffler (Jan 15 2024 at 15:46):

Here's a 2-line proof:

lemma the_calculation {x : } (hx : x  0) (h2 : x  1) :
    -1 / (1 - x) / log 2 - x⁻¹ / log 2 = -1 / (x * (1 - x) * log 2) := by
  field_simp [sub_ne_zero.mpr h2.symm]
  ring

The point is that field_simp takes an optional argument, which is a list of proofs that things are not zero. Here sub_ne_zero.mpr h2.symm is a proof that 1 - x ≠ 0, which is the information field_simp needs to clear denominators.


Last updated: May 02 2025 at 03:31 UTC