Zulip Chat Archive
Stream: new members
Topic: zero divisors and nilpotents
Aniruddh Agarwal (May 17 2020 at 17:53):
Which definition would be considered better:
def is_nilpotent [comm_ring α] (a : α) := ∃ n : ℕ, a ^ n = 0
def is_nilpotent' [comm_ring α] {n : ℕ} (a : α) := a ^ n = 0
Kevin Buzzard (May 17 2020 at 17:53):
Top one
Kevin Buzzard (May 17 2020 at 17:54):
The bottom one would be hard to use because in most cases Lean would not be able to guess n
.
Patrick Stevens (May 17 2020 at 17:54):
The bottom one would force the user to know the witness to nilpotence, right?
Patrick Stevens (May 17 2020 at 17:54):
^^
Aniruddh Agarwal (May 17 2020 at 19:10):
I've almost proved that nonzero nilpotents are zero divisors, I just need to prove
theorem nonzero_nilpotent_has_nonzero_power [comm_ring α] :
∀ a : α, a ≠ 0 → is_nilpotent a → ∃ m : ℕ, a^m ≠ 0 ∧ ∀ n : ℕ, n > m → a^n = 0
:= sorry
to get it, but I'm stumped. I want to find m
by taking the minimum of the set (type?) { n : ℕ | a^n = 0 }
, but I'm not sure how to set that up. Here's where I'm at so far:
import algebra.associated
import algebra.group_power
variables {α : Type*}
/- An element a of a ring α is a zero divisor if there exists a b ∈ α
such that b ≠ 0 and ab = 0. -/
def is_zero_divisor [comm_ring α] (a : α) := ∃ b : α, b ≠ 0 ∧ a * b = 0
/- An element a of a ring α is nilpotent if there exists a n ∈ ℕ such
that n ≠ 0 and a^n = 0 -/
def is_nilpotent [comm_ring α] (a : α) := ∃ n : ℕ, n ≠ 0 ∧ a ^ n = 0
/- If a is a nonzero nilpotent, then we can find a nonzero natural m
such that a^m ≠ 0 and a^n = 0 for all n > m. -/
theorem nonzero_nilpotent_has_nonzero_power [comm_ring α] :
∀ a : α, a ≠ 0 → is_nilpotent a → ∃ m : ℕ, a^m ≠ 0 ∧ ∀ n : ℕ, n > m → a^n = 0
:=
begin
unfold is_nilpotent,
intros a hanz hanlp,
have set := { n : ℕ | a^n = 0 },
sorry,
end
I apparently can't just write min set
to get the minimum because lean can't find an instance of a decidable_linear_order
for N
. Any advice?
Bhavik Mehta (May 17 2020 at 19:13):
Try going classical, it might be the decidability that causes issues
Aniruddh Agarwal (May 17 2020 at 19:15):
Sorry, can you be more specific?
Bhavik Mehta (May 17 2020 at 19:15):
In this specific case though, nat.find
is what you probably should use
Bhavik Mehta (May 17 2020 at 19:18):
begin
classical,
unfold is_nilpotent,
intros a hanz hanlp,
let property : ℕ → Prop := λ n, a^n = 0,
have there_is_some : ∃ n, property n,
sorry,
let m := nat.find there_is_some,
have : a^m = 0 := nat.find_spec there_is_some,
end
Bhavik Mehta (May 17 2020 at 19:19):
Here's a sketch of how you might use nat.find
Bhavik Mehta (May 17 2020 at 19:19):
(in your case, the property maybe should be a^n ≠ 0
, I haven't checked)
Mario Carneiro (May 17 2020 at 19:20):
I guess it could just be the existential in is_nilpotent
: ∃ n : ℕ, n ≠ 0 ∧ a ^ n = 0
Bhavik Mehta (May 17 2020 at 19:20):
That could work too
Bhavik Mehta (May 17 2020 at 19:21):
@Aniruddh Agarwal, you might also like to note that I used let
instead of have
sometimes - have
doesn't keep track of the actual definition, just its type (so it's the right sort of thing for properties, since we don't care about what the actual proof was) but let
does keep track of how it was defined
Reid Barton (May 17 2020 at 19:29):
n ≠ 0
is unnecessary; is there a reason to include it?
Mario Carneiro (May 17 2020 at 19:39):
In this case you probably want to find the least m
such that a^(m+1)=0
Aniruddh Agarwal (May 17 2020 at 20:53):
@Bhavik Mehta I've slightly modified your sketch to get to
begin
classical,
unfold is_nilpotent,
intros a hanz hanlp,
have there_is_some : ∃ n, a^(n+1) = 0,
sorry,
have m := nat.find_min' there_is_some,
end
which is almost what I want, except that m
's type
m : (λ (n : ℕ), a ^ (n + 1) = 0) ?m_1 → nat.find there_is_some ≤ ?m_1
contains a dummy variable ?m_1
Bhavik Mehta (May 17 2020 at 20:55):
The dummy variable represents a natural you haven't chosen yet
Bhavik Mehta (May 17 2020 at 20:55):
Once the dummy variable is picked (I'll call it t
), m
would have type a^(t + 1) = 0 → nat.find there_is_some ≤ t
Bhavik Mehta (May 17 2020 at 20:58):
Have a look at the functions around nat.find
to see what you're given to work with:
protected def find : ℕ := nat.find_x.1
protected theorem find_spec : p nat.find := nat.find_x.2.left
protected theorem find_min : ∀ {m : ℕ}, m < nat.find → ¬p m := nat.find_x.2.right
protected theorem find_min' {m : ℕ} (h : p m) : nat.find ≤ m :=
le_of_not_gt (λ l, find_min l h)
Aniruddh Agarwal (May 17 2020 at 22:11):
I'm still confused and unable to get the minimum of that set out using those functions around nat.find
:/
Kevin Buzzard (May 17 2020 at 22:15):
Look at the type of nat.find
. That tells you what it does. What is your exact problem? Post some working code
Aniruddh Agarwal (May 17 2020 at 22:46):
There is where I'm currently stuck:
import algebra.associated
import algebra.group_power
variables {α : Type*}
/- An element a of a ring α is nilpotent if there exists a n ∈ ℕ such
that a^n = 0. -/
def is_nilpotent [comm_ring α] (a : α) := ∃ n : ℕ, n ≠ 0 ∧ a ^ n = 0
/- If a is a nonzero nilpotent, then we can find a nonzero natural m
such that a^m ≠ 0 and a^n = 0 for all n > m. -/
theorem nonzero_nilpotent_has_nonzero_power [comm_ring α] :
∀ a : α, a ≠ 0 → is_nilpotent a → ∃ m : ℕ, a^m ≠ 0 ∧ ∀ n : ℕ, n > m → a^n = 0
:=
begin
classical,
unfold is_nilpotent,
intros a hanz hanlp,
have there_is_some : ∃ n, a^(n+1) = 0,
cases hanlp with n hn,
cases n with,
have bad := hn.left,
contradiction,
constructor,
rw nat.succ_eq_add_one at hn,
exact hn.right,
have m := nat.find there_is_some,
have hm := nat.find_min' there_is_some,
constructor,
split,
-- I want to show that m satisfies a^(m+1)=0
sorry,
sorry,
sorry,
sorry,
end
Kevin Buzzard (May 17 2020 at 22:47):
Can we please change the definition of nilpotent by dropping the n != 0 condition?
Kevin Buzzard (May 17 2020 at 22:47):
It just makes things harder
Kevin Buzzard (May 17 2020 at 22:49):
oh but then your proof will need refactoring
Mario Carneiro (May 17 2020 at 22:50):
You forgot to use nat.find_spec
Reid Barton (May 17 2020 at 22:51):
Do you need this statement? How about there exists m
such that a^m = 0
and a^n \ne 0
for n < m
?
Kevin Buzzard (May 17 2020 at 22:52):
Yes what you're doing does look like an unnatural thing to prove
Kevin Buzzard (May 17 2020 at 22:53):
let m := nat.find there_is_some,
not have
Kevin Buzzard (May 17 2020 at 22:57):
Reid's suggestion is better because it doesn't involve this unnatural hypothesis about a being non-zero.
Kevin Buzzard (May 17 2020 at 22:59):
Why not fix the definition of nilpotent and then prove what Reid suggests?
Kevin Buzzard (May 17 2020 at 23:02):
The trick with these things is to find the right statement which doesn't have special cases such as "doesn't work if a=0".
Mario Carneiro (May 17 2020 at 23:05):
How about \exists m, \forall n, a^n = 0 <-> m <= n
Mario Carneiro (May 17 2020 at 23:06):
everything is better with iff
Kevin Buzzard (May 17 2020 at 23:07):
import algebra.associated
import algebra.group_power
variables {α : Type*}
open_locale classical
/- An element a of a ring α is nilpotent if there exists a n ∈ ℕ such
that a^n = 0. -/
def is_nilpotent [comm_ring α] (a : α) := ∃ n : ℕ, a ^ n = 0
/- If a is a nonzero nilpotent, then we can find a nonzero natural m
such that a^m ≠ 0 and a^n = 0 for all n > m. -/
theorem nonzero_nilpotent_has_nonzero_power [comm_ring α] :
∀ a : α, is_nilpotent a → ∃ m : ℕ, a^m = 0 ∧ ∀ n : ℕ, n < m → a^n ≠ 0
:=
begin
rintros a hna,
use nat.find hna,
split,
{ exact nat.find_spec hna},
{ intro n,
exact nat.find_min hna}
end
Kevin Buzzard (May 17 2020 at 23:07):
Reid's version comes out really nicely.
Kevin Buzzard (May 17 2020 at 23:08):
Mario's version will also come out nicely
Reid Barton (May 17 2020 at 23:20):
- such that a^m ≠ 0 and a^n = 0 for all n > m. -/
+ such that a^m = 0 and a^n ≠ 0 for all n < m. -/
Kevin Buzzard (May 18 2020 at 09:49):
@Aniruddh Agarwal here is a way of thinking about all this. You want to find a way of expressing, in Lean, the following idea: if a is nilpotent, and you look at the function from to which sends to the truth-value of the question "Is ?", then this function looks like "F,F,F,...,F,...,F,T,T,T,...,T,T,...". This is an idea, not a formalised statement. There are lots of different ways to formalise it. You chose one way, which treated the case a=0 as a special case (where the function looks like "T,T,T,T,..." or "F,T,T,T,..." depending on whether R is the zero ring or not) but one could just as well prove the lemma that said that a=0 iff a^n=0 for all n>=1, which would be a much nicer way of dealing with a=0 rather than trying to formalise something general and then leaving out the a=0 case. Leaving in a=0 for now, we want to formalise the idea that there will be 0 or more F's, but a finite number, followed by a bunch of T's. Because 0 F's is possible (if R=0 and a=0) we should let the "key" natural number be the first T, rather than the last F (which might not exist in general). If you are in a situation where you want the index of the last F assuming a isn't zero, you'll be able to get it by subtracting 1 from the first T. But the more natural lemma is the one which applies for all a, rather than just non-zero a.
In short, the lemmas which one wants to formalise are the ones with the most natural statements and the fewest edge cases.
Jalex Stark (May 18 2020 at 13:23):
of course the things kevin says about picking natural statements is also true when doing "paper maths", but human mathematicians can elaborate away the "trivial" edge-cases
Aniruddh Agarwal (May 18 2020 at 18:42):
:sigh: I finally finished the proof that nonzero nilpotents are zero divisors: https://github.com/anrddh/commutative-algebra-playground/blob/master/src/zero_divisors_and_nilpotents.lean#L45
Aniruddh Agarwal (May 18 2020 at 18:45):
Thanks all for your substantial help
Kevin Buzzard (May 18 2020 at 18:54):
theorem nz_nilpotent_is_zerodivisor [comm_ring α] :
∀ a : α, is_nilpotent a → a ≠ 0 → is_zero_divisor a
:=
begin
rintros a ha ha',
rcases exists_min_pow_zero_of_nilpotent a ha with ⟨m, hm1, hm2⟩,
cases m with m,
{ -- a^0=0 can't happen
exfalso,
apply ha',
apply eq_zero_of_zero_eq_one,
rw ←hm1,
refl
},
{ use a^m,
split,
{ apply hm2,
exact lt_add_one m
},
rw ←hm1,
rw pow_succ
}
end
Kevin Buzzard (May 18 2020 at 18:55):
You shouldn't really use simp
in the middle of proofs, they will break later on as simp
gets smarter.
Kevin Buzzard (May 18 2020 at 19:02):
/- All nonzero nilpotents are zerodivisors. -/
theorem nz_nilpotent_is_zerodivisor [comm_ring α] (a : α) (ha : is_nilpotent a) (ha' : a ≠ 0) : is_zero_divisor a
:=
let ⟨m, hm1, hm2⟩ := exists_min_pow_zero_of_nilpotent a ha in
begin
cases m with m,
{ exact false.elim (ha' (eq_zero_of_zero_eq_one _ hm1.symm _))},-- a^0=0 can't happen
{ exact ⟨a^m, hm2 _ (lt_add_one m), hm1⟩}
end
Kevin Buzzard (May 18 2020 at 19:06):
I can't figure out how to get the cases
into term mode, but if I could this could be a completely term mode proof. The term proof is the same as the tactic proof, each tactic can be turned into a term.
Patrick Stevens (May 18 2020 at 19:06):
Note that it's perfectly fine to use simp
if you phrase things so that simp
is doing something specific. For example, have something : foo, by simp
is safe: even if simp
gets smarter, it's not going to start doing awful things to your proof state, because it's been restricted to this one little fragment of proof.
Patrick Stevens (May 18 2020 at 19:08):
(Although for efficiency, mathlib uses squeeze_simp
to discover a more minimal subset of things that simp
would use, and then restricts the call to simp
using only
so that it only uses those things)
Patrick Stevens (May 18 2020 at 19:16):
Kevin Buzzard said:
I can't figure out how to get the
cases
into term mode, but if I could this could be a completely term mode proof. The term proof is the same as the tactic proof, each tactic can be turned into a term.
I'm not sure it's possible, although my confidence here is weak - exists_min_pow_zero_of_nilpotent
has output a Prop
existential, but to extract anything from this in term mode you'd need a Type
, wouldn't you?
Kevin Buzzard (May 18 2020 at 19:26):
Patrick Stevens said:
I'm not sure it's possible, although my confidence here is weak -
exists_min_pow_zero_of_nilpotent
has output aProp
existential, but to extract anything from this in term mode you'd need aType
, wouldn't you?
I don't know, this is all a bit CS for me.
Alex J. Best (May 18 2020 at 19:33):
/- All nonzero nilpotents are zerodivisors. -/
theorem nz_nilpotent_is_zerodivisor' [comm_ring α] (a : α) (ha : is_nilpotent a) (ha' : a ≠ 0) : is_zero_divisor a
:= match exists_min_pow_zero_of_nilpotent a ha with
| ⟨0, hm1, hm2⟩ := false.elim (ha' (eq_zero_of_zero_eq_one _ hm1.symm _))
| ⟨(m+1), hm1, hm2⟩ := ⟨a^m, hm2 _ (lt_add_one m), hm1⟩
end
terms are love, terms are life
Mario Carneiro (May 18 2020 at 20:07):
Patrick Stevens said:
I'm not sure it's possible, although my confidence here is weak -
exists_min_pow_zero_of_nilpotent
has output aProp
existential, but to extract anything from this in term mode you'd need aType
, wouldn't you?
exists_min_pow_zero_of_nilpotent
can be proven in Type
, since it has an explicit witness, namely nat.find
of some stuff
Last updated: Dec 20 2023 at 11:08 UTC