Skip to content

Commit

Permalink
feat(AlgebraicGeometry): Π Rᵢ-points of schemes (#20494)
Browse files Browse the repository at this point in the history
  • Loading branch information
erdOne committed Jan 30, 2025
1 parent dc2c587 commit 344e1cf
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 2 deletions.
1 change: 1 addition & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,7 @@ import Mathlib.AlgebraicGeometry.Morphisms.UniversallyInjective
import Mathlib.AlgebraicGeometry.Noetherian
import Mathlib.AlgebraicGeometry.OpenImmersion
import Mathlib.AlgebraicGeometry.Over
import Mathlib.AlgebraicGeometry.PointsPi
import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Basic
import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Proper
import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Scheme
Expand Down
9 changes: 9 additions & 0 deletions Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,15 @@ def Spec.homEquiv {R S : CommRingCat} : (Spec S ⟶ Spec R) ≃ (R ⟶ S) where
left_inv := Spec.map_preimage
right_inv := Spec.preimage_map

@[simp]
lemma Spec.preimage_id {R : CommRingCat} : Spec.preimage (𝟙 (Spec R)) = 𝟙 R :=
Spec.map_injective (by simp)

@[simp, reassoc]
lemma Spec.preimage_comp {R S T : CommRingCat} (f : Spec R ⟶ Spec S) (g : Spec S ⟶ Spec T) :
Spec.preimage (f ≫ g) = Spec.preimage g ≫ Spec.preimage f :=
Spec.map_injective (by simp)

end

instance : Spec.toLocallyRingedSpace.IsRightAdjoint :=
Expand Down
57 changes: 56 additions & 1 deletion Mathlib/AlgebraicGeometry/Limits.lean
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,36 @@ lemma sigmaMk_mk (i) (x : f i) :
refine (colimit.isoColimitCocone_ι_inv_assoc ⟨_, TopCat.sigmaCofanIsColimit _⟩ _ _).trans ?_
exact ι_comp_sigmaComparison Scheme.forgetToTop _ _

open scoped Function in
lemma isOpenImmersion_sigmaDesc
{X : Scheme} (α : ∀ i, f i ⟶ X) [∀ i, IsOpenImmersion (α i)]
(hα : Pairwise (Disjoint on (Set.range <| α · |>.base))) :
IsOpenImmersion (Sigma.desc α) := by
rw [IsOpenImmersion.iff_stalk_iso]
constructor
· suffices Topology.IsOpenEmbedding ((Sigma.desc α).base ∘ sigmaMk f) by
convert this.comp (sigmaMk f).symm.isOpenEmbedding; ext; simp
refine .of_continuous_injective_isOpenMap ?_ ?_ ?_
· fun_prop
· rintro ⟨ix, x⟩ ⟨iy, y⟩ e
have : (α ix).base x = (α iy).base y := by
simpa [← Scheme.comp_base_apply] using e
obtain rfl : ix = iy := by
by_contra h
exact Set.disjoint_iff_forall_ne.mp (hα h) ⟨x, rfl⟩ ⟨y, this.symm⟩ rfl
rw [(α ix).isOpenEmbedding.injective this]
· rw [isOpenMap_sigma]
intro i
simpa [← Scheme.comp_base_apply] using (α i).isOpenEmbedding.isOpenMap
· intro x
have ⟨y, hy⟩ := (sigmaOpenCover f).covers x
rw [← hy]
refine IsIso.of_isIso_fac_right (g := ((sigmaOpenCover f).map _).stalkMap y)
(h := (X.presheaf.stalkCongr (.of_eq ?_)).hom ≫ (α _).stalkMap _) ?_
· simp [← Scheme.comp_base_apply]
· simp [← Scheme.stalkMap_comp, Scheme.stalkMap_congr_hom _ _ (Sigma.ι_desc _ _)]


variable (X Y : Scheme.{u})

/-- (Implementation Detail)
Expand Down Expand Up @@ -498,11 +528,36 @@ noncomputable
def sigmaSpec (R : ι → CommRingCat) : (∐ fun i ↦ Spec (R i)) ⟶ Spec (.of (Π i, R i)) :=
Sigma.desc (fun i ↦ Spec.map (CommRingCat.ofHom (Pi.evalRingHom _ i)))

@[simp, reassoc]
@[reassoc (attr := simp)]
lemma ι_sigmaSpec (R : ι → CommRingCat) (i) :
Sigma.ι _ i ≫ sigmaSpec R = Spec.map (CommRingCat.ofHom (Pi.evalRingHom _ i)) :=
Sigma.ι_desc _ _

instance (i) (R : ι → Type _) [∀ i, CommRing (R i)] :
IsOpenImmersion (Spec.map (CommRingCat.ofHom (Pi.evalRingHom (R ·) i))) := by
classical
letI := (Pi.evalRingHom R i).toAlgebra
have : IsLocalization.Away (Function.update (β := R) 0 i 1) (R i) := by
apply IsLocalization.away_of_isIdempotentElem_of_mul
· ext j; by_cases h : j = i <;> aesop
· intro x y
constructor
· intro e; ext j; by_cases h : j = i <;> aesop
· intro e; simpa using congr_fun e i
· exact Function.surjective_eval _
exact IsOpenImmersion.of_isLocalization (Function.update 0 i 1)

instance (R : ι → CommRingCat) : IsOpenImmersion (sigmaSpec R) := by
classical
apply isOpenImmersion_sigmaDesc
intro ix iy h
refine Set.disjoint_iff_forall_ne.mpr ?_
rintro _ ⟨x, rfl⟩ _ ⟨y, rfl⟩ e
have : DFinsupp.single (β := (R ·)) iy 1 iy ∈ y.asIdeal :=
(PrimeSpectrum.ext_iff.mp e).le (x := DFinsupp.single iy 1)
(show DFinsupp.single (β := (R ·)) iy 1 ix ∈ x.asIdeal by simp [h.symm])
simp [← Ideal.eq_top_iff_one, y.2.ne_top] at this

instance [Finite ι] (R : ι → CommRingCat) : IsIso (sigmaSpec R) := by
have : sigmaSpec R =
(colimit.isoColimitCocone ⟨_,
Expand Down
20 changes: 20 additions & 0 deletions Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,26 @@ theorem isAffine_surjective_of_isAffine [IsClosedImmersion f] :
((affineTargetImageFactorization f).appTop)).surjective.comp <|
affineTargetImageInclusion_app_surjective f⟩

lemma Spec_iff {R : CommRingCat} {f : X ⟶ Spec R} :
IsClosedImmersion f ↔ ∃ I : Ideal R, ∃ e : X ≅ Spec (.of <| R ⧸ I),
f = e.hom ≫ Spec.map (CommRingCat.ofHom (Ideal.Quotient.mk I)) := by
constructor
· intro H
obtain ⟨h₁, h₂⟩ := IsClosedImmersion.isAffine_surjective_of_isAffine f
let φ := (Scheme.ΓSpecIso R).inv ≫ f.appTop
refine ⟨RingHom.ker φ.1, Scheme.isoSpec _ ≪≫ Scheme.Spec.mapIso
(.op (RingEquiv.ofBijective φ.1.kerLift ?_).toCommRingCatIso), ?_⟩
· exact ⟨φ.1.kerLift_injective, Ideal.Quotient.lift_surjective_of_surjective _ _
(h₂.comp (Scheme.ΓSpecIso R).commRingCatIsoToRingEquiv.symm.surjective)⟩
· simp only [Iso.trans_hom, Functor.mapIso_hom, Iso.op_hom, Scheme.Spec_map,
Quiver.Hom.unop_op, Category.assoc, ← Spec.map_comp]
show f = X.isoSpec.hom ≫ Spec.map φ
simp only [Scheme.isoSpec, asIso_hom, Spec.map_comp, ← Scheme.toSpecΓ_naturality_assoc,
← SpecMap_ΓSpecIso_hom, φ]
simp only [← Spec.map_comp, Iso.inv_hom_id, Spec.map_id, Category.comp_id]
· rintro ⟨I, e, rfl⟩
infer_instance

end IsClosedImmersion

end Affine
Expand Down
11 changes: 10 additions & 1 deletion Mathlib/AlgebraicGeometry/Morphisms/Immersion.lean
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ if and only if it can be factored into a closed immersion followed by an open im

universe v u

open CategoryTheory
open CategoryTheory Limits

namespace AlgebraicGeometry

Expand Down Expand Up @@ -172,6 +172,15 @@ instance : IsImmersion (pullback.diagonal f) := by
rwa [morphismRestrict_ι, H, ← Scheme.topIso_hom,
MorphismProperty.cancel_left_of_respectsIso (P := @IsImmersion)] at this

instance : IsImmersion (prod.lift (𝟙 X) (𝟙 X)) := by
rw [← MorphismProperty.cancel_right_of_respectsIso @IsImmersion _ (prodIsoPullback X X).hom]
convert inferInstanceAs (IsImmersion (pullback.diagonal (terminal.from X)))
ext : 1 <;> simp

instance (f g : X ⟶ Y) : IsImmersion (equalizer.ι f g) :=
MorphismProperty.of_isPullback (P := @IsImmersion)
(isPullback_equalizer_prod f g).flip inferInstance

end IsImmersion

end AlgebraicGeometry
21 changes: 21 additions & 0 deletions Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Authors: Andrew Yang
-/
import Mathlib.AlgebraicGeometry.Morphisms.Constructors
import Mathlib.AlgebraicGeometry.Morphisms.QuasiCompact
import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Equalizer
import Mathlib.Topology.QuasiSeparated
import Mathlib.Topology.Sheaves.CommRingCat

Expand Down Expand Up @@ -170,6 +171,26 @@ theorem IsAffineOpen.isQuasiSeparated {X : Scheme} {U : X.Opens} (hU : IsAffineO
rw [isQuasiSeparated_iff_quasiSeparatedSpace]
exacts [@AlgebraicGeometry.quasiSeparatedSpace_of_isAffine _ hU, U.isOpen]

lemma quasiSeparatedSpace_iff_quasiCompact_prod_lift :
QuasiSeparatedSpace X ↔ QuasiCompact (prod.lift (𝟙 X) (𝟙 X)) := by
rw [← MorphismProperty.cancel_right_of_respectsIso @QuasiCompact _ (prodIsoPullback X X).hom,
← HasAffineProperty.iff_of_isAffine (f := terminal.from X) (P := @QuasiSeparated),
quasiSeparated_iff]
congr!
ext : 1 <;> simp

instance [QuasiSeparatedSpace X] : QuasiCompact (prod.lift (𝟙 X) (𝟙 X)) := by
rwa [← quasiSeparatedSpace_iff_quasiCompact_prod_lift]

instance [QuasiSeparatedSpace Y] (f g : X ⟶ Y) : QuasiCompact (equalizer.ι f g) :=
MorphismProperty.of_isPullback (P := @QuasiCompact)
(isPullback_equalizer_prod f g).flip inferInstance

instance [CompactSpace X] [QuasiSeparatedSpace Y] (f g : X ⟶ Y) :
CompactSpace (equalizer f g).carrier := by
constructor
simpa using QuasiCompact.isCompact_preimage (f := equalizer.ι f g) _ isOpen_univ isCompact_univ

theorem QuasiSeparated.of_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [QuasiSeparated (f ≫ g)] :
QuasiSeparated f := by
let 𝒰 := (Z.affineCover.pullbackCover g).bind fun x => Scheme.affineCover _
Expand Down
145 changes: 145 additions & 0 deletions Mathlib/AlgebraicGeometry/PointsPi.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/-
Copyright (c) 2024 Andrew Yang. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andrew Yang
-/
import Mathlib.AlgebraicGeometry.Morphisms.Immersion

/-!
# `Π Rᵢ`-Points of Schemes
We show that the canonical map `X(Π Rᵢ) ⟶ Π X(Rᵢ)` (`AlgebraicGeometry.pointsPi`)
is injective and surjective under various assumptions
-/

open CategoryTheory Limits PrimeSpectrum

namespace AlgebraicGeometry

universe u v

variable {ι : Type u} (R : ι → CommRingCat.{u})

lemma Ideal.span_eq_top_of_span_image_evalRingHom
{ι} {R : ι → Type*} [∀ i, CommRing (R i)] (s : Set (Π i, R i))
(hs : s.Finite) (hs' : ∀ i, Ideal.span (Pi.evalRingHom (R ·) i '' s) = ⊤) :
Ideal.span s = ⊤ := by
simp only [Ideal.eq_top_iff_one, ← Subtype.range_val (s := s), ← Set.range_comp,
Finsupp.mem_ideal_span_range_iff_exists_finsupp] at hs' ⊢
choose f hf using hs'
have : Fintype s := hs.fintype
refine ⟨Finsupp.equivFunOnFinite.symm fun i x ↦ f x i, ?_⟩
ext i
simpa [Finsupp.sum_fintype] using hf i

lemma eq_top_of_sigmaSpec_subset_of_isCompact
(U : (Spec (.of (Π i, R i))).Opens) (V : Set (Spec (.of (Π i, R i))))
(hV : ↑(sigmaSpec R).opensRange ⊆ V)
(hV' : IsCompact (X := Spec (.of (Π i, R i))) V)
(hVU : V ⊆ U) : U = ⊤ := by
obtain ⟨s, hs⟩ := (PrimeSpectrum.isOpen_iff _).mp U.2
obtain ⟨t, hts, ht, ht'⟩ : ∃ t ⊆ s, t.Finite ∧ V ⊆ ⋃ i ∈ t, (basicOpen i).1 := by
obtain ⟨t, ht⟩ := hV'.elim_finite_subcover
(fun i : s ↦ (basicOpen i.1).1) (fun _ ↦ (basicOpen _).2)
(by simpa [← Set.compl_iInter, ← zeroLocus_iUnion₂ (κ := (· ∈ s)), ← hs])
exact ⟨t.map (Function.Embedding.subtype _), by simp, Finset.finite_toSet _, by simpa using ht⟩
replace ht' : V ⊆ (zeroLocus t)ᶜ := by
simpa [← Set.compl_iInter, ← zeroLocus_iUnion₂ (κ := (· ∈ t))] using ht'
have (i) : Ideal.span (Pi.evalRingHom (R ·) i '' t) = ⊤ := by
rw [← zeroLocus_empty_iff_eq_top, zeroLocus_span, ← preimage_comap_zeroLocus,
← Set.compl_univ_iff, ← Set.preimage_compl, Set.preimage_eq_univ_iff]
trans (Sigma.ι _ i ≫ sigmaSpec R).opensRange.1
· simp; rfl
· rw [Scheme.Hom.opensRange_comp]
exact (Set.image_subset_range _ _).trans (hV.trans ht')
have : Ideal.span s = ⊤ := top_le_iff.mp
((Ideal.span_eq_top_of_span_image_evalRingHom _ ht this).ge.trans (Ideal.span_mono hts))
simpa [← zeroLocus_span s, zeroLocus_empty_iff_eq_top.mpr this] using hs

lemma eq_bot_of_comp_quotientMk_eq_sigmaSpec (I : Ideal (Π i, R i))
(f : (∐ fun i ↦ Spec (R i)) ⟶ Spec (.of ((Π i, R i) ⧸ I)))
(hf : f ≫ Spec.map (CommRingCat.ofHom (Ideal.Quotient.mk I)) = sigmaSpec R) :
I = ⊥ := by
refine le_bot_iff.mp fun x hx ↦ ?_
ext i
simpa [← Category.assoc, Ideal.Quotient.eq_zero_iff_mem.mpr hx] using
congr((Spec.preimage (Sigma.ι (Spec <| R ·) i ≫ $hf)).hom x).symm

/-- If `V` is a locally closed subscheme of `Spec (Π Rᵢ)` containing `∐ Spec Rᵢ`, then
`V = Spec (Π Rᵢ)`. -/
lemma isIso_of_comp_eq_sigmaSpec {V : Scheme}
(f : (∐ fun i ↦ Spec (R i)) ⟶ V) (g : V ⟶ Spec (.of (Π i, R i)))
[IsImmersion g] [CompactSpace V]
(hU' : f ≫ g = sigmaSpec R) : IsIso g := by
have : g.coborderRange = ⊤ := by
apply eq_top_of_sigmaSpec_subset_of_isCompact (hVU := subset_coborder)
· simpa only [← hU'] using Set.range_comp_subset_range f.base g.base
· exact isCompact_range g.base.2
have : IsClosedImmersion g := by
have : IsIso g.coborderRange.ι := by rw [this, ← Scheme.topIso_hom]; infer_instance
rw [← g.liftCoborder_ι]
infer_instance
obtain ⟨I, e, rfl⟩ := IsClosedImmersion.Spec_iff.mp this
obtain rfl := eq_bot_of_comp_quotientMk_eq_sigmaSpec R I (f ≫ e.hom) (by rwa [Category.assoc])
show IsIso (e.hom ≫ Spec.map (RingEquiv.quotientBot _).toCommRingCatIso.inv)
infer_instance

variable (X : Scheme)

/-- The canonical map `X(Π Rᵢ) ⟶ Π X(Rᵢ)`.
This is injective if `X` is quasi-separated, surjective if `X` is affine,
or if `X` is compact and each `Rᵢ` is local. -/
noncomputable
def pointsPi : (Spec (.of (Π i, R i)) ⟶ X) → Π i, Spec (R i) ⟶ X :=
fun f i ↦ Spec.map (CommRingCat.ofHom (Pi.evalRingHom (R ·) i)) ≫ f

lemma pointsPi_injective [QuasiSeparatedSpace X] : Function.Injective (pointsPi R X) := by
rintro f g e
have := isIso_of_comp_eq_sigmaSpec R (V := equalizer f g)
(equalizer.lift (sigmaSpec R) (by ext1 i; simpa using congr_fun e i))
(equalizer.ι f g) (by simp)
rw [← cancel_epi (equalizer.ι f g), equalizer.condition]

lemma pointsPi_surjective_of_isAffine [IsAffine X] : Function.Surjective (pointsPi R X) := by
rintro f
refine ⟨Spec.map (CommRingCat.ofHom
(Pi.ringHom fun i ↦ (Spec.preimage (f i ≫ X.isoSpec.hom)).1)) ≫ X.isoSpec.inv, ?_⟩
ext i : 1
simp only [pointsPi, ← Spec.map_comp_assoc, Iso.comp_inv_eq]
exact Spec.map_preimage _

lemma pointsPi_surjective [CompactSpace X] [∀ i, IsLocalRing (R i)] :
Function.Surjective (pointsPi R X) := by
intro f
let 𝒰 : X.OpenCover := X.affineCover.finiteSubcover
have (i) : IsAffine (𝒰.obj i) := isAffine_Spec _
have (i) : ∃ j, Set.range (f i).base ⊆ (𝒰.map j).opensRange := by
refine ⟨𝒰.f ((f i).base (IsLocalRing.closedPoint (R i))), ?_⟩
rintro _ ⟨x, rfl⟩
exact ((IsLocalRing.specializes_closedPoint x).map (f i).base.2).mem_open
(𝒰.map _).opensRange.2 (𝒰.covers _)
choose j hj using this
have (j₀) := pointsPi_surjective_of_isAffine (ι := { i // j i = j₀ }) (R ·) (𝒰.obj j₀)
(fun i ↦ IsOpenImmersion.lift (𝒰.map j₀) (f i.1) (by rcases i with ⟨i, rfl⟩; exact hj i))
choose g hg using this
simp_rw [funext_iff, pointsPi] at hg
let R' (j₀) := CommRingCat.of (Π i : { i // j i = j₀ }, R i)
let e : (Π i, R i) ≃+* Π j₀, R' j₀ :=
{ toFun f _ i := f i
invFun f i := f _ ⟨i, rfl⟩
left_inv _ := rfl
right_inv _ := funext₂ fun j₀ i ↦ by rcases i with ⟨i, rfl⟩; rfl
map_mul' _ _ := rfl
map_add' _ _ := rfl }
refine ⟨Spec.map (CommRingCat.ofHom e.symm.toRingHom) ≫ inv (sigmaSpec R') ≫
Sigma.desc fun j₀ ↦ g j₀ ≫ 𝒰.map j₀, ?_⟩
ext i : 1
have : (Pi.evalRingHom (R ·) i).comp e.symm.toRingHom =
(Pi.evalRingHom _ ⟨i, rfl⟩).comp (Pi.evalRingHom (R' ·) (j i)) := rfl
rw [pointsPi, ← Spec.map_comp_assoc, ← CommRingCat.ofHom_comp, this, CommRingCat.ofHom_comp,
Spec.map_comp_assoc, ← ι_sigmaSpec R', Category.assoc, IsIso.hom_inv_id_assoc,
Sigma.ι_desc, ← Category.assoc, hg, IsOpenImmersion.lift_fac]

end AlgebraicGeometry

0 comments on commit 344e1cf

Please sign in to comment.