Zulip Chat Archive
Stream: Is there code for X?
Topic: tactic for easy calculations in ZMod p?
David Renshaw (Jun 17 2023 at 13:24):
import Mathlib.Data.ZMod.Basic
lemma foo (a b : ZMod 7) (h : a + 3 * b = 0) : a = 4 * b := by
-- is there a tactic that can avoid all of this manual rewriting?
have h9: a + 3 * b - 3 * b = 0 - 3 * b := congrFun (congrArg HSub.hSub h) _
rwa [add_sub_cancel, zero_sub, ←neg_mul, show ((-3):ZMod 7) = 4 by rfl] at h9
Is there a tactic that can automate this proof?
David Renshaw (Jun 17 2023 at 13:24):
(that code is Lean 4)
Yaël Dillies (Jun 17 2023 at 13:42):
What about (untested)
rw [show (4 : zmod 7) = -3, by norm_num]
linear_combination h
David Renshaw (Jun 17 2023 at 13:44):
Nice!
import Mathlib.Data.ZMod.Basic
import Mathlib.Tactic.LinearCombination
lemma lemma2 (a b : ZMod 7) (h : a + 3 * b = 0) : a = 4 * b := by
rw [show (4 : ZMod 7) = -3 by norm_num]
linear_combination h
David Renshaw (Jun 17 2023 at 13:50):
And it succeeds in context: https://github.com/dwrensha/math-puzzles-in-lean4/commit/a7526ac929ae14aaa95983f1dea4d2b0b2b17bb5
Thanks!
Anne Baanen (Jun 19 2023 at 08:41):
Yaël Dillies said:
What about (untested)
rw [show (4 : zmod 7) = -3, by norm_num] linear_combination h
Last time I checked, norm_num
doesn't have any specific support for ZMod
so I believe the norm_num
call is just a complicated way to write dec_trivial
. I was actually looking into making a tactic that goes through an expression in characteristic p
and rewrites all coefficients to be between 0
and p
. My Lean4 metaprogramming skills aren't quite good enough to make it work yet though :P
David Renshaw (Jun 19 2023 at 11:23):
just plain rfl
seems to work for me
David Renshaw (Jun 19 2023 at 11:45):
Makes me wonder why linear_combination
needs this hint from me.
Eric Wieser (Jun 19 2023 at 11:50):
Well 4 = 11
and infinitely many other similar statements are also true by rfl
...
Eric Wieser (Jun 19 2023 at 11:51):
Polyrith can solve things like this after #17142
David Renshaw (Jun 19 2023 at 15:03):
Well 4 = 11 and infinitely many other similar statements are also true by rfl
My (naive) reasoning is:
linear_combination
is chaining together a bunch ofring
invocationsring
is stronger thanring_nf
, which is "ring normal form", and "normal form" means normalizing all terms(-3 : ZMod 7)
should normalize to4
, (as should(11 : ZMod 7)
).
Eric Wieser (Jun 19 2023 at 15:08):
"normal form" means "normal form in the language of rings", not "normal form in whatever ring you happen to be using"
Eric Wieser (Jun 19 2023 at 15:12):
Somewhat surprisingly, ring
can't even solve:
lemma lemma2 (R) [Ring R] (x : R) : 1 + x + 1 = x + 2 := by ring
Alex J. Best (Jun 19 2023 at 15:25):
Thats probably as ring is designed for CommRings, so its probably silently falling back to not doing very much at all (maybe it even thinks it's working on the nats inside the ofnat notation).
Alex J. Best (Jun 19 2023 at 15:30):
It would certainly be nice to normalize to some normal form for rings of some fixed explicitly given characteristic in addition, but we don't have a tactic that does that yet, @Anne Baanen was working on something like this in lean 3 I believe. EDIT: oops I see Anne already mentioned this above :wink:
Anne Baanen (Jun 19 2023 at 15:31):
I am working on this in Lean 4 right as we speak!
Eric Wieser (Jun 19 2023 at 15:50):
Alex J. Best said:
Thats probably as ring is designed for CommRings
This gets me every time...
Eric Wieser (Jun 19 2023 at 15:50):
Can we call it comm_ring_nf
to make that clear?
Ruben Van de Velde (Jun 19 2023 at 15:53):
crnf?
Eric Wieser (Jun 19 2023 at 17:03):
I don't think we need to make it short since no one ever types ring_nf
anyway
Eric Wieser (Jun 19 2023 at 17:03):
I'm pretty sure every use of it exists because Try this
generated it when someone typed ring
Jireh Loreaux (Jun 19 2023 at 18:55):
my brain really wants "crnf" to mean "carriage return / newline feed" :laughing:
Heather Macbeth (Jun 19 2023 at 20:01):
To return to the original problem, you don't need to state some fact like (4 : zmod 7) = -3
that's particularly relevant to the problem. You can just write out whatever the defining features of your ring are and then include them in your linear_combination
calculation.
lemma lemma2 (a b : ZMod 7) (h : a + 3 * b = 0) : a = 4 * b := by
have h2 : (7:ZMod 7) = 0 := rfl
linear_combination h - b * h2
Heather Macbeth (Jun 19 2023 at 20:01):
See also the discussion for at
https://hrmacbeth.github.io/computations_in_lean/02_Using_Polyrith.html#isometries-of-the-complex-plane
Anne Baanen (Jun 22 2023 at 09:20):
My tactic is now PR'd as #5376!
Yury G. Kudryashov (Jun 25 2023 at 03:17):
In Coq (note: I don't know the details), tactics like ring
and field
allow type-specific plugins for things like IsNumeral
and "is n = m
?"
Yury G. Kudryashov (Jun 25 2023 at 03:18):
I guess, mathlib
uses norm_num
for this and only deals rational constants.
Yury G. Kudryashov (Jun 25 2023 at 03:19):
Is it possible to write a norm_num
plugins that knows about CharP
?
Yury G. Kudryashov (Jun 25 2023 at 03:19):
Disclaimer: I know nothing about internals of norm_num
.
Mario Carneiro (Jun 25 2023 at 03:21):
depends on what you mean, what is triggering the plugin to be called?
Yury G. Kudryashov (Jun 25 2023 at 03:23):
E.g., ring
wants to know whether 2 = 5
or not
Yury G. Kudryashov (Jun 25 2023 at 03:24):
Or ring
never wants this, it wants to normalize the coefficient?
Mario Carneiro (Jun 25 2023 at 03:24):
that's right
Yury G. Kudryashov (Jun 25 2023 at 03:25):
Can we have some normalize
operation with plugins, then? (Part of) #5376 can be one of them.
Mario Carneiro (Jun 25 2023 at 03:26):
most likely this can't be done with plugins, you would need to change parts of the core
Mario Carneiro (Jun 25 2023 at 03:27):
I think that has the same issue, what induces the plugin to be called? Why is it not calling all plugins on every number all the time?
Mario Carneiro (Jun 25 2023 at 03:27):
there needs to be some kind of trigger which isn't always true
Yury G. Kudryashov (Jun 25 2023 at 03:41):
Can it call all plugins on the final result of the computation in Rat
? Or will it be too slow?
Yury G. Kudryashov (Jun 25 2023 at 03:41):
(e.g., since failing an instance search for CharP
can be slow)
Mario Carneiro (Jun 25 2023 at 03:48):
how final is final? Anything that is happening inside ring
is called a ton of times
Mario Carneiro (Jun 25 2023 at 03:49):
note that in lean 3 there was a separate tactic norm_fin
that handled this reasoning
Anne Baanen (Jun 26 2023 at 15:13):
Yury G. Kudryashov said:
In Coq (note: I don't know the details), tactics like
ring
andfield
allow type-specific plugins for things likeIsNumeral
and "isn = m
?"
This is one of the reasons I implemented reduce_mod_char
, Assia was somewhat shocked that this functionality wasn't available in our ring
:)
Anne Baanen (Jun 26 2023 at 15:18):
If I recall correctly, in Coq the user specifies which coefficients to use in a call to ring
. Based on some quick Lean 3 experiments, it should be possible in our implementation to define a record with info on how to recognize/add/subtract/multiply coefficients, and a zero-test. If the user writes ring
, we put the ℚ
version of this record, if the user writes ring zmod 5
we use zmod 5
, etc.
Anne Baanen (Jun 26 2023 at 15:20):
reduce_mod_char
is more like norm_fin
in that it looks at the type to figure out the characteristic, rather than using typeclass inference. Unlike norm_fin
, reduce_mod_char
also supports polynomials over zmod n
, etc.
Eric Rodriguez (Jun 26 2023 at 15:23):
Is it easy to write override this in case it can't be figured out, e.g. reduce_mod_char p
will use inference to find the right instance?
Anne Baanen (Jun 27 2023 at 09:32):
The problem isn't so much figuring out the characteristic of a single expression, as it is figuring out which subexpressions are eligible for rewriting. I suppose we could a heuristic to drill down to the "interesting" expressions (e.g. if we see $a = $b
, try $a
and $b
) and then try rewriting any of their subexpressions with the same type. But that seems quite fragile: what if we want to show Polynomial.natDegree ((3 * X^3 : (ZMod 3)[X]) = 0
?
Eric Rodriguez (Jun 27 2023 at 09:46):
I'm suggesting a mixed approach - the approach you suggest usually, but if you are given an explicit p
, then assume all expressions containing any sort of numeral could be subject to this and look at typeclass search.
Eric Rodriguez (Jun 27 2023 at 09:47):
Because as I see it, this approach doesn't work if you're working over K [char_p p K]
Johan Commelin (Jun 27 2023 at 09:51):
It was discussed to make p
an outparam of CharP
. That would help here, right?
Anne Baanen (Jun 27 2023 at 10:28):
Johan Commelin said:
It was discussed to make
p
an outparam ofCharP
. That would help here, right?
I certainly expect it would not hurt, although Lean 4 is slightly more willing to find instances when there are still metavariables in the goal.
Alex J. Best (Jun 27 2023 at 21:11):
@Anne Baanen does reduce_mod_char
normalize rational expressions too btw?
Anne Baanen (Jun 28 2023 at 10:21):
There is no special handling for those, beyond using norm_num
's machinery to parse expressions. Could you give an example of something you'd like the tactic to handle?
Alex J. Best (Jun 28 2023 at 10:45):
E.g. to turn (1 : Zmod 2)/ 3
into 1
(or more interestingly for larger numbers of course!
Maybe that one already works actually. But (1 : Zmod 5)/ 2
into 3
would be non-trivial
Anne Baanen (Jun 28 2023 at 10:50):
That's indeed along the same lines as I was thinking, thanks for confirming! I couldn't actually figure out how to make (1 : Zmod 5)/ 2
elaborate correctly, there is no HDiv
instance and adding a Fact (Prime 5)
hypothesis didn't seem to help...
Johan Commelin (Jun 28 2023 at 10:55):
But that should yield a field instance, shouldn't it?
Johan Commelin (Jun 28 2023 at 10:55):
Sounds like a bug
Johan Commelin (Jun 28 2023 at 10:57):
import Mathlib.Data.ZMod.Basic
import Mathlib.Tactic.FieldSimp
example (p : ℕ) [Fact p.Prime] : Field (ZMod p) := inferInstance
example [Fact (Nat.Prime 5)] : (1 : ZMod 5) / 2 = 3 := by
have : (2 : ZMod 5) ≠ 0 := ne_of_beq_false rfl
field_simp
rfl
Johan Commelin (Jun 28 2023 at 10:57):
Probably Prime
was not elaborating to Nat.Prime
in your example
Anne Baanen (Jun 28 2023 at 12:04):
I indeed forgot Nat.Prime != Prime
:sweat_smile:
Anne Baanen (Jun 28 2023 at 12:07):
(Now that docs#Nat.Prime is defined in terms of the ring structure, would it be worth removing it altogether to avoid this kind of confusion?)
Johan Commelin (Jun 28 2023 at 12:07):
But it is defined to be Irreducible
, right?
Anne Baanen (Jun 28 2023 at 12:33):
Oh yeah... I suppose that matches more closely with the standard notion of "only divisible by 1 and itself". Looks like one year ago the plan was to get rid of Nat.Prime
altogether: https://leanprover.zulipchat.com/#narrow/stream/144837-PR-reviews/topic/.2312709.20-.20redefine.20nat.2Eprime.20as.20prime
Last updated: Dec 20 2023 at 11:08 UTC