Zulip Chat Archive

Stream: general

Topic: Dealing with 0 * 0 not defeq 0 in Rat


Joseph Tooby-Smith (Nov 01 2024 at 16:43):

I'm trying to bump HepLean from 4.12.0 to 4.13.0. But I'm running into a problem.

There are a number of results which are complicated expressions in the rationals that are actually equal to zero.
In 4.12.0 these could be solved with`rfl' but now they can't. I think this boils down to the fact that for 4.12.0

import Mathlib

example : (0 : ) * 0 = 0 := by
  rfl

works but does not work in 4.13.0 (I'm unsure about the releases in-between).

I can't actually seem to find the change which means this no longer works, but in any case, are there any suggestions on how I overcome this? The tactic `norm_num' etc does not work for the expressions that I have.

Kyle Miller (Nov 01 2024 at 17:07):

The change is that well-founded recursion is irreducible by default now. You can "unseal" such definitions on a case-by-case basis:

unseal Rat.mul in
example : (0 : ) * 0 = 0 := by
  rfl

Eric Wieser (Nov 01 2024 at 17:32):

I'm guessing this comes up in dimensional analysis?

Eric Wieser (Nov 01 2024 at 17:32):

Can you give an example of norm_num failing?

Joseph Tooby-Smith (Nov 01 2024 at 21:27):

@Eric Wieser These sort of things actually came up solving what are called the anomaly cancellation conditions. These are a set of polynomials in the rational parameters (which correspond to physical charges one can assign to the fermions which make up the universe). The polynomials must be zero for a theory to be well defined.

Here is a toy example of norm_num failing:

import Mathlib

def f : Fin 4   := ![0, 1, 3, 4]

example :  f 0 + f 0  * f 0 + f 0 = 0 := by
  norm_num

The actual examples I have are of a similar variety but a lot more complicated, meaning it is unfeasible to unfold all of the definitions. Here is an example of one of the theorems which is actually breaking.

I'll try @Kyle Miller suggestion tomorrow. Many thanks

Eric Wieser (Nov 01 2024 at 21:31):

example :  f 0 + f 0  * f 0 + f 0 = 0 := by
  norm_num [f]

works there

Yury G. Kudryashov (Nov 02 2024 at 03:10):

Relying on definitional equality is a very fragile design pattern. It can break for reasons out of your control.

Joseph Tooby-Smith (Nov 02 2024 at 05:13):

@Eric Wieser Ok, the following example is more representative of the problem I'm facing:

import Mathlib


example :   x : Fin 3,
        (![1, (0 : ), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((0 : Fin 6), x)) *
        ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((0 : Fin 6), x)) +
      -(2 * (![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((1 : Fin 6), x)) * ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((1 : Fin 6), x)))) +
      ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((2 : Fin 6), x)) * ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((2 : Fin 6), x)) + -(![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((3 : Fin 6), x)) *
      ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((3 : Fin 6), x))) +
      ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((4 : Fin 6), x)) *
      ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((4 : Fin 6), x))) = 0 := by
    norm_num

@Yury G. Kudryashov Indeed - seems like I'm suffering the consequences of this now.

Daniel Weber (Nov 02 2024 at 05:28):

native_decide gives a very weird error message here

application type mismatch
  Lean.ofReduceBool _example._nativeDecide_1 true (Eq.refl true)
argument has type
  true = true
but function has type
  Lean.reduceBool _example._nativeDecide_1 = true  _example._nativeDecide_1 = true

Daniel Weber (Nov 02 2024 at 05:29):

It's actually equal to one, not zero, and you can use with_unfolding_all decide to prove it:

import Mathlib

example :   x : Fin 3,
        (![1, (0 : ), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((0 : Fin 6), x)) *
        ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((0 : Fin 6), x)) +
      -(2 * (![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((1 : Fin 6), x)) * ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((1 : Fin 6), x)))) +
      ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((2 : Fin 6), x)) * ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((2 : Fin 6), x)) + -(![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((3 : Fin 6), x)) *
      ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((3 : Fin 6), x))) +
      ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((4 : Fin 6), x)) *
      ![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (finProdFinEquiv ((4 : Fin 6), x))) = 1 := by
    with_unfolding_all decide

Joseph Tooby-Smith (Nov 02 2024 at 05:55):

@Daniel Weber Indeed, that was my fault. This should actually equal 1.
Thanks for the with_unfolding_all decide tactic idea! This seems to work for my general cases.


Last updated: May 02 2025 at 03:31 UTC