Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ring_theory/algebraic): algebraic extensions, algebraic elements #1519

Merged
merged 35 commits into from
Oct 16, 2019
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
40e74d7
chore(ring_theory/algebra): make first type argument explicit in alg_hom
ChrisHughes24 Aug 3, 2019
790c892
Update algebra.lean
ChrisHughes24 Aug 3, 2019
c0633b5
feat(field_theory/algebraic_closure)
ChrisHughes24 Aug 3, 2019
931bf08
Merge branch 'master' into algebraic_closure
ChrisHughes24 Aug 4, 2019
7fff9f3
Merge branch 'lean-3.4.2' into algebraic_closure
jcommelin Aug 26, 2019
e01a15e
Remove sorries about minimal polynomials
jcommelin Aug 26, 2019
2aff46a
Define alg_equiv.symm
jcommelin Aug 26, 2019
d5c4897
typo
jcommelin Aug 26, 2019
71ed4b5
Remove another sorry, in base_extension
jcommelin Aug 26, 2019
067984e
Work in progress
jcommelin Aug 26, 2019
b64985a
Remove a sorry in maximal_extension_chain
jcommelin Aug 26, 2019
25080c9
Merge two sorries
jcommelin Aug 27, 2019
ca7c85d
More sorries removed
jcommelin Aug 27, 2019
542fca8
More work on transitivity of algebraicity
jcommelin Aug 27, 2019
f3620a6
WIP
jcommelin Aug 27, 2019
cac8632
Sorry-free definition of algebraic closure
jcommelin Aug 28, 2019
6915af4
More or less sorries
jcommelin Aug 28, 2019
a4fb375
Removing some sorries
jcommelin Aug 29, 2019
3079d38
WIP
jcommelin Aug 29, 2019
4f0378c
Merge branch 'lean-3.4.2' into algebraic_closure
jcommelin Oct 7, 2019
a81fb91
Fix algebraic.lean
jcommelin Oct 7, 2019
62e7e1d
Fix build, mostly
jcommelin Oct 7, 2019
6f06db7
Remove stuff about UMP of alg clos
jcommelin Oct 8, 2019
747a854
Prove transitivity of algebraic extensions
jcommelin Oct 8, 2019
51ae389
Add some docstrings
jcommelin Oct 8, 2019
d4c3d3d
Remove files with stuff for future PRs
jcommelin Oct 8, 2019
e6f412f
Add a bit to the module docstring
jcommelin Oct 8, 2019
38e46cb
Fix module docstring
jcommelin Oct 8, 2019
1ffc6a4
Include assumption in section injective
jcommelin Oct 9, 2019
267064b
Aesthetic changes to is_integral_of_mem_of_fg
jcommelin Oct 9, 2019
5cb7a17
Little improvements of proofs in algebraic.lean
jcommelin Oct 9, 2019
2c9afb2
Improve some proofs in integral_closure.lean
jcommelin Oct 9, 2019
303116b
Make variable name explicit
jcommelin Oct 9, 2019
b86edf4
Process comments
jcommelin Oct 14, 2019
9b46823
Merge branch 'master' into algebraic-trans
jcommelin Oct 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 132 additions & 84 deletions src/data/polynomial.lean
Original file line number Diff line number Diff line change
Expand Up @@ -398,76 +398,6 @@ by unfold comp; apply_instance

end comp

section map
variables [comm_semiring β]
variables (f : α → β)

/-- `map f p` maps a polynomial `p` across a ring hom `f` -/
def map : polynomial α → polynomial β := eval₂ (C ∘ f) X

variables [is_semiring_hom f]

@[simp] lemma map_C : (C a).map f = C (f a) := eval₂_C _ _

@[simp] lemma map_X : X.map f = X := eval₂_X _ _

@[simp] lemma map_zero : (0 : polynomial α).map f = 0 := eval₂_zero _ _

@[simp] lemma map_add : (p + q).map f = p.map f + q.map f := eval₂_add _ _

@[simp] lemma map_one : (1 : polynomial α).map f = 1 := eval₂_one _ _

@[simp] lemma map_mul : (p * q).map f = p.map f * q.map f := eval₂_mul _ _

instance map.is_semiring_hom : is_semiring_hom (map f) := eval₂.is_semiring_hom _ _

lemma map_pow (n : ℕ) : (p ^ n).map f = p.map f ^ n := eval₂_pow _ _ _

lemma coeff_map (n : ℕ) : coeff (p.map f) n = f (coeff p n) :=
begin
rw [map, eval₂, coeff_sum],
conv_rhs { rw [← sum_C_mul_X_eq p, coeff_sum, finsupp.sum,
← finset.sum_hom f], },
refine finset.sum_congr rfl (λ x hx, _),
simp [function.comp, coeff_C_mul_X, is_semiring_hom.map_mul f],
split_ifs; simp [is_semiring_hom.map_zero f],
end

lemma map_map {γ : Type*} [comm_semiring γ] (g : β → γ) [is_semiring_hom g]
(p : polynomial α) : (p.map f).map g = p.map (λ x, g (f x)) :=
ext (by simp [coeff_map])

lemma eval₂_map {γ : Type*} [comm_semiring γ] (g : β → γ) [is_semiring_hom g] (x : γ) :
(p.map f).eval₂ g x = p.eval₂ (λ y, g (f y)) x :=
polynomial.induction_on p
(by simp)
(by simp [is_semiring_hom.map_add f] {contextual := tt})
(by simp [is_semiring_hom.map_mul f,
is_semiring_hom.map_pow f, pow_succ', (mul_assoc _ _ _).symm] {contextual := tt})

lemma eval_map (x : β) : (p.map f).eval x = p.eval₂ f x := eval₂_map _ _ _

@[simp] lemma map_id : p.map id = p := by simp [id, polynomial.ext_iff, coeff_map]

end map

section
variables {γ : Type*} [comm_semiring β] [comm_semiring γ]
variables (f : α → β) (g : β → γ) [is_semiring_hom f] [is_semiring_hom g] (p)

lemma hom_eval₂ (x : β) : g (p.eval₂ f x) = p.eval₂ (g ∘ f) (g x) :=
begin
apply polynomial.induction_on p; clear p,
{ intros a, rw [eval₂_C, eval₂_C] },
{ intros p q hp hq, simp only [hp, hq, eval₂_add, is_semiring_hom.map_add g] },
{ intros n a ih,
replace ih := congr_arg (λ y, y * g x) ih,
simpa [pow_succ', is_semiring_hom.map_mul g, (mul_assoc _ _ _).symm,
eval₂_C, eval₂_mul, eval₂_X] using ih }
end

end

/-- `leading_coeff p` gives the coefficient of the highest power of `X` in `p`-/
def leading_coeff (p : polynomial α) : α := coeff p (nat_degree p)

Expand Down Expand Up @@ -609,6 +539,89 @@ begin
finset.sum_mul_boole, finset_sum_coeff, ite_le_nat_degree_coeff],
end

section map
rwbarton marked this conversation as resolved.
Show resolved Hide resolved
variables [comm_semiring β]
variables (f : α → β)

/-- `map f p` maps a polynomial `p` across a ring hom `f` -/
def map : polynomial α → polynomial β := eval₂ (C ∘ f) X

variables [is_semiring_hom f]

@[simp] lemma map_C : (C a).map f = C (f a) := eval₂_C _ _

@[simp] lemma map_X : X.map f = X := eval₂_X _ _

@[simp] lemma map_zero : (0 : polynomial α).map f = 0 := eval₂_zero _ _

@[simp] lemma map_add : (p + q).map f = p.map f + q.map f := eval₂_add _ _

@[simp] lemma map_one : (1 : polynomial α).map f = 1 := eval₂_one _ _

@[simp] lemma map_mul : (p * q).map f = p.map f * q.map f := eval₂_mul _ _

instance map.is_semiring_hom : is_semiring_hom (map f) := eval₂.is_semiring_hom _ _

@[simp] lemma map_pow (n : ℕ) : (p ^ n).map f = p.map f ^ n := eval₂_pow _ _ _

lemma coeff_map (n : ℕ) : coeff (p.map f) n = f (coeff p n) :=
begin
rw [map, eval₂, coeff_sum],
conv_rhs { rw [← sum_C_mul_X_eq p, coeff_sum, finsupp.sum,
← finset.sum_hom f], },
refine finset.sum_congr rfl (λ x hx, _),
simp [function.comp, coeff_C_mul_X, is_semiring_hom.map_mul f],
split_ifs; simp [is_semiring_hom.map_zero f],
end

lemma map_map {γ : Type*} [comm_semiring γ] (g : β → γ) [is_semiring_hom g]
(p : polynomial α) : (p.map f).map g = p.map (λ x, g (f x)) :=
ext (by simp [coeff_map])

lemma eval₂_map {γ : Type*} [comm_semiring γ] (g : β → γ) [is_semiring_hom g] (x : γ) :
(p.map f).eval₂ g x = p.eval₂ (λ y, g (f y)) x :=
polynomial.induction_on p
(by simp)
(by simp [is_semiring_hom.map_add f] {contextual := tt})
(by simp [is_semiring_hom.map_mul f,
is_semiring_hom.map_pow f, pow_succ', (mul_assoc _ _ _).symm] {contextual := tt})

lemma eval_map (x : β) : (p.map f).eval x = p.eval₂ f x := eval₂_map _ _ _

@[simp] lemma map_id : p.map id = p := by simp [id, polynomial.ext_iff, coeff_map]

lemma mem_map_range {p : polynomial β} :
p ∈ set.range (map f) ↔ ∀ n, p.coeff n ∈ (set.range f) :=
begin
split,
{ rintro ⟨p, rfl⟩ n, rw coeff_map, exact set.mem_range_self _ },
{ intro h, rw p.as_sum,
apply is_add_submonoid.finset_sum_mem,
intros i hi,
rcases h i with ⟨c, hc⟩,
use [C c * X^i],
rw [map_mul, map_C, hc, map_pow, map_X] }
end

end map

section
variables {γ : Type*} [comm_semiring β] [comm_semiring γ]
variables (f : α → β) (g : β → γ) [is_semiring_hom f] [is_semiring_hom g] (p)

lemma hom_eval₂ (x : β) : g (p.eval₂ f x) = p.eval₂ (g ∘ f) (g x) :=
begin
apply polynomial.induction_on p; clear p,
{ intros a, rw [eval₂_C, eval₂_C] },
{ intros p q hp hq, simp only [hp, hq, eval₂_add, is_semiring_hom.map_add g] },
{ intros n a ih,
replace ih := congr_arg (λ y, y * g x) ih,
simpa [pow_succ', is_semiring_hom.map_mul g, (mul_assoc _ _ _).symm,
eval₂_C, eval₂_mul, eval₂_X] using ih }
end

end

lemma coeff_nat_degree_eq_zero_of_degree_lt (h : degree p < degree q) : coeff p (nat_degree q) = 0 :=
coeff_eq_zero_of_degree_lt (lt_of_lt_of_le h degree_le_nat_degree)

Expand Down Expand Up @@ -730,6 +743,14 @@ leading_coeff_monomial 1 0

@[simp] lemma monic_one : monic (1 : polynomial α) := leading_coeff_C _

lemma monic.ne_zero_of_zero_ne_one (h : (0:α) ≠ 1) {p : polynomial α} (hp : p.monic) :
p ≠ 0 :=
by { contrapose! h, rwa [h] at hp }

lemma monic.ne_zero {α : Type*} [nonzero_comm_ring α] {p : polynomial α} (hp : p.monic) :
p ≠ 0 :=
hp.ne_zero_of_zero_ne_one $ zero_ne_one

lemma leading_coeff_add_of_degree_lt (h : degree p < degree q) :
leading_coeff (p + q) = leading_coeff q :=
have coeff p (nat_degree q) = 0, from coeff_nat_degree_eq_zero_of_degree_lt h,
Expand Down Expand Up @@ -886,13 +907,6 @@ le_antisymm (degree_map_le f) $
rw [coeff_map], exact hf
end

lemma degree_map_eq_of_injective [comm_semiring β] (f : α → β) [is_semiring_hom f]
(hf : function.injective f) : degree (p.map f) = degree p :=
if h : p = 0 then by simp [h]
else degree_map_eq_of_leading_coeff_ne_zero _
(by rw [← is_semiring_hom.map_zero f]; exact mt hf.eq_iff.1
(mt leading_coeff_eq_zero.1 h))

lemma monic_map [comm_semiring β] (f : α → β)
[is_semiring_hom f] (hp : monic p) : monic (p.map f) :=
if h : (0 : β) = 1 then
Expand Down Expand Up @@ -952,15 +966,49 @@ by simpa only [C_1, one_mul] using degree_C_mul_X_pow_le (1:α) n
theorem degree_X_le : degree (X : polynomial α) ≤ 1 :=
by simpa only [C_1, one_mul, pow_one] using degree_C_mul_X_pow_le (1:α) 1

lemma degree_map' [comm_semiring β] (p : polynomial α)
{f : α → β} [is_semiring_hom f] (hf : function.injective f) :
section injective
open function
variables [comm_semiring β] {f : α → β} [is_semiring_hom f] (hf : function.injective f)
include hf

lemma degree_map_eq_of_injective (p : polynomial α) : degree (p.map f) = degree p :=
if h : p = 0 then by simp [h]
else degree_map_eq_of_leading_coeff_ne_zero _
(by rw [← is_semiring_hom.map_zero f]; exact mt hf.eq_iff.1
(mt leading_coeff_eq_zero.1 h))

lemma degree_map' (p : polynomial α) :
degree (p.map f) = degree p :=
degree_map_eq_of_injective _ hf
p.degree_map_eq_of_injective hf

lemma nat_degree_map' [comm_semiring β] (p : polynomial α)
{f : α → β} [is_semiring_hom f] (hf : function.injective f) :
lemma nat_degree_map' (p : polynomial α) :
nat_degree (p.map f) = nat_degree p :=
nat_degree_eq_of_degree_eq (degree_map' _ hf)
nat_degree_eq_of_degree_eq (degree_map' hf p)

lemma map_injective (p : polynomial α) :
injective (map f : polynomial α → polynomial β) :=
λ p q h, ext $ λ m, hf $
begin
rw ext_iff at h,
specialize h m,
rw [coeff_map f, coeff_map f] at h,
exact h
end

lemma leading_coeff_of_injective (p : polynomial α) :
leading_coeff (p.map f) = f (leading_coeff p) :=
begin
delta leading_coeff,
rw [coeff_map f, nat_degree_map' hf p]
end

lemma monic_of_injective {p : polynomial α} (hp : (p.map f).monic) : p.monic :=
begin
apply hf,
rw [← leading_coeff_of_injective hf, hp.leading_coeff, is_semiring_hom.map_one f]
end

end injective

theorem monic_of_degree_le (n : ℕ) (H1 : degree p ≤ n) (H2 : coeff p n = 1) : monic p :=
decidable.by_cases
Expand Down Expand Up @@ -2093,7 +2141,7 @@ by rw [div_def, mul_comm, degree_mul_leading_coeff_inv _ hq0];

@[simp] lemma degree_map [discrete_field β] (p : polynomial α) (f : α → β) [is_field_hom f] :
degree (p.map f) = degree p :=
degree_map_eq_of_injective _ (is_field_hom.injective f)
p.degree_map_eq_of_injective (is_field_hom.injective f)

@[simp] lemma nat_degree_map [discrete_field β] (f : α → β) [is_field_hom f] :
nat_degree (p.map f) = nat_degree p :=
Expand Down
2 changes: 1 addition & 1 deletion src/field_theory/minimal_polynomial.lean
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ variable (β)
/--If L/K is a field extension, and x is an element of L in the image of K,
then the minimal polynomial of x is X - C x.-/
lemma algebra_map' (a : α) :
minimal_polynomial (@is_integral_algebra_map α β _ _ _ _ _ a) =
minimal_polynomial (@is_integral_algebra_map α β _ _ _ a) =
X - C a :=
minimal_polynomial.algebra_map _ _
variable {β}
Expand Down
89 changes: 89 additions & 0 deletions src/ring_theory/algebraic.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/-
Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin
-/

import ring_theory.integral_closure

/-!
# Algebraic elements and algebraic extensions

An element of an R-algebra is algebraic over R if it is the root of a nonzero polynomial.
An R-algebra is algebraic over R if and only if all its elements are algebraic over R.
The main result in this file proves transitivity of algebraicity:
a tower of algebraic field extensions is algebraic.
-/

universe variables u v

open_locale classical
open polynomial

section
variables (R : Type u) {A : Type v} [comm_ring R] [comm_ring A] [algebra R A]

/-- An element of an R-algebra is algebraic over R if it is the root of a nonzero polynomial. -/
def is_algebraic (x : A) : Prop :=
∃ p : polynomial R, p ≠ 0 ∧ aeval R A x p = 0

variables {R}

/-- A subalgebra is algebraic if all its elements are algebraic. -/
def subalgebra.is_algebraic (S : subalgebra R A) : Prop := ∀ x ∈ S, is_algebraic R x
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to introduce is_algebraic for subalgebras first? It looks like "compact subset" again.
Why not just define algebra.is_algebraic directly and then say a subalgebra is algebraic if it is algebraic as an algebra?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way I think you will eventually want to prove that a subalgebra S is algebraic in the sense of algebra.is_algebraic if and only if it is algebraic in the sense of this current subalgebra.is_algebraic (right?). To me algebra.is_algebraic seems like the primary notion so defining it directly looks better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More or less done. They now all have elementwise definitions and iffs relating the various definitions.


variables (R A)

/-- An algebra is algebraic if it is algebraic as a subalgebra. -/
def algebra.is_algebraic : Prop := (⊤ : subalgebra R A).is_algebraic

variables {R A}

/-- An algebra is algebraic if and only if all its elements are algebraic. -/
lemma algebra.is_algebraic_iff : algebra.is_algebraic R A ↔ ∀ x : A, is_algebraic R x :=
begin
delta algebra.is_algebraic subalgebra.is_algebraic,
simp only [algebra.mem_top, forall_prop_of_true, iff_self],
end

end

section zero_ne_one
variables (R : Type u) {A : Type v} [nonzero_comm_ring R] [comm_ring A] [algebra R A]

/-- An integral element of an algebra is algebraic.-/
lemma is_integral.is_algebraic {x : A} (h : is_integral R x) : is_algebraic R x :=
by { rcases h with ⟨p, hp, hpx⟩, exact ⟨p, hp.ne_zero, hpx⟩ }

end zero_ne_one

section field
variables (K : Type u) {A : Type v} [discrete_field K] [comm_ring A] [algebra K A]

/-- An element of an algebra over a field is algebraic if and only if it is integral.-/
lemma is_algebraic_iff_is_integral {x : A} :
is_algebraic K x ↔ is_integral K x :=
begin
refine ⟨_, is_integral.is_algebraic K⟩,
rintro ⟨p, hp, hpx⟩,
refine ⟨_, monic_mul_leading_coeff_inv hp, _⟩,
rw [alg_hom.map_mul, hpx, zero_mul],
end

end field

namespace algebra
variables {K : Type*} {L : Type*} {A : Type*}
variables [discrete_field K] [discrete_field L] [comm_ring A]
variables [algebra K L] [algebra L A]

/-- If L is an algebraic field extension of K and A is an algebraic algebra over L,
then A is algebraic over K. -/
lemma is_algebraic_trans (L_alg : is_algebraic K L) (A_alg : is_algebraic L A) :
is_algebraic K (comap K L A) :=
begin
simp only [is_algebraic_iff, is_algebraic_iff_is_integral] at L_alg A_alg ⊢,
exact is_integral_trans L_alg A_alg,
end

end algebra
Loading