Skip to content

Commit

Permalink
Fiber products (#3129)
Browse files Browse the repository at this point in the history
* Introduce PrincipalOpenInclusion s.

* Implement fiber products
  • Loading branch information
HechtiDerLachs authored Jan 10, 2024
1 parent 4d087fb commit 448c2f9
Show file tree
Hide file tree
Showing 24 changed files with 1,090 additions and 44 deletions.
5 changes: 5 additions & 0 deletions docs/src/AlgebraicGeometry/Schemes/CoveredSchemes.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ An `AbsCoveredScheme` may have different properties such as
is_smooth(X::AbsCoveredScheme)
```

## Methods
```@docs
fiber_product(f::AbsCoveredSchemeMorphism, g::AbsCoveredSchemeMorphism)
```

## The modeling of covered schemes and their expected behaviour

Any `AbsCoveredScheme` may possess several `Covering`s. This is necessary for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ is_identity_map(f::AbsSpecMor)
## Methods

```@docs
fiber_product(f::SpecMor{SpecType, SpecType, <:Any}, g::SpecMor{SpecType, SpecType, <:Any}) where {SpecType<:StdSpec}
fiber_product(f::AbsSpecMor, g::AbsSpecMor)
product(X::AbsSpec, Y::AbsSpec)
simplify(X::AbsSpec{<:AbstractAlgebra.Field})
```
3 changes: 2 additions & 1 deletion experimental/Schemes/CoherentSheaves.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1445,7 +1445,8 @@ end
for U in patches(C)
V = __find_chart(U, default_covering(X))
phi = OOX(V, U)
set_decomposition_info!(C, U, phi.(decomposition_info(default_covering(X))[V]))
new_info = Vector{elem_type(OO(U))}(phi.(decomposition_info(default_covering(X))[V]))
set_decomposition_info!(C, U, new_info)
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,4 @@ function restrict(f::SpecMor, U::AbsSpec, V::AbsSpec; check::Bool=true)
@check issubset(U, preimage(f, V)) "the image of the restriction is not contained in the restricted codomain"
return SpecMor(U, V, (x->OO(U)(x, check=check)).(pullback(f).(gens(domain(pullback(f))))), check=check)
end

224 changes: 213 additions & 11 deletions src/AlgebraicGeometry/Schemes/AffineSchemes/Morphisms/Methods.jl
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@



###########################################################
# (1) The fibre product of two morphisms of affine schemes
###########################################################

@doc raw"""
fiber_product(f::SpecMor{SpecType, SpecType, <:Any}, g::SpecMor{SpecType, SpecType, <:Any}) where {SpecType<:StdSpec}
fiber_product(f::AbsSpecMor, g::AbsSpecMor)
For morphisms ``f : X → Z`` and ``g : Y → Z`` return the fiber
product ``X×Y`` over ``Z`` together with its two canonical projections.
For morphisms ``f : Y → X`` and ``g : Z → X`` return the fiber
product ``Y×Z`` over ``X`` together with its two canonical projections.
Whenever you have another set of maps `a: W → X` and `b : W → Y` forming
a commutative square with `f` and `g`, you can use
`induced_map_to_fiber_product` to create the resulting map `W → X×Y`.
"""
function fiber_product(
f::SpecMor{SpecType, SpecType, <:Any},
g::SpecMor{SpecType, SpecType, <:Any}
) where {SpecType<:StdSpec}
f::AbsSpecMor,
g::AbsSpecMor
)
Y = domain(f)
X = codomain(f)
X == codomain(g) || error("maps need to have the same codomain")
Expand All @@ -25,7 +26,209 @@ function fiber_product(
return W, restrict(pY, W, Y, check=false), restrict(pZ, W, Z, check=false)
end

# Whenever one of the maps, say f, in a fiber product is a `PrincipalOpenEmbedding`
# then the fiber product is only the restriction of g to g^{-1}(image(f)).
# This can be computed much easier and, in particular, without introducing
# extra variables: One just pulls back the `complement_equations` for `f` to
# the domain of `g`.
#
# We need this more simple procedure for refinements of coverings. In particular,
# it is important that the resulting fiber product is a PrincipalOpenSubset of
# the domain of `g` (or the domain of `f` when it's the other way around), so that
# the ancestry-tree for patches is preserved.
function fiber_product(f::PrincipalOpenEmbedding, g::AbsSpecMor)
@assert codomain(f) === codomain(g) "codomains are not the same"
A = domain(f)
B = domain(g)
C = codomain(f)
h = complement_equations(f)
pbh = pullback(g).(h)
result = PrincipalOpenSubset(B, pbh)
ff = PrincipalOpenEmbedding(SpecMor(result, B, gens(OO(result)), check=false), pbh, check=false)
f_res_inv = inverse_on_image(f)
gg = compose(restrict(g, result, image(f), check=false), f_res_inv)
return result, gg, ff
end

function fiber_product(f::AbsSpecMor, g::PrincipalOpenEmbedding)
result, ff, gg = fiber_product(g, f)
return result, gg, ff
end

# additional method to remove method ambiguity
function fiber_product(f::PrincipalOpenEmbedding, g::PrincipalOpenEmbedding)
@assert codomain(f) === codomain(g) "codomains are not the same"
A = domain(f)
B = domain(g)
C = codomain(f)
h = complement_equations(f)
pbh = pullback(g).(h)
result = PrincipalOpenSubset(B, pbh)
ff = PrincipalOpenEmbedding(SpecMor(result, B, gens(OO(result)), check=false), pbh, check=false)
f_res_inv = inverse_on_image(f)
gg = compose(restrict(g, result, image(f), check=false), f_res_inv)
hg = complement_equations(g)
pbhg = pullback(f).(hg)
return result, PrincipalOpenEmbedding(gg, pbhg, check=false), ff
end

@doc raw"""
induced_map_to_fiber_product(
a::AbsSpecMor, b::AbsSpecMor,
f::AbsSpecMor, g::AbsSpecMor;
fiber_product::Tuple{<:AbsSpec, <:AbsSpecMor, <:AbsSpecMor}=fiber_product(f, g)
)
In a commutative diagram
```
b
W ------------.
| |
| V
a| X x Y -->Y
| | | g
| V V
`----->X----> Z
f
```
this computes the canonical map `W -> X x Y`.
"""
function induced_map_to_fiber_product(
a::AbsSpecMor, b::AbsSpecMor,
f::AbsSpecMor, g::AbsSpecMor;
fiber_product::Tuple{<:AbsSpec, <:AbsSpecMor, <:AbsSpecMor}=fiber_product(f, g),
check::Bool=true
)
# All checks are done here. The actual computations are carried out
# in an internal method.
X = domain(f)
Y = domain(g)
Z = codomain(f)
@assert codomain(g) === Z
XxY = fiber_product[1]
gg = fiber_product[2]
ff = fiber_product[3]
@assert codomain(ff) === Y
@assert codomain(gg) === X

W = domain(a)
@assert W === domain(b)
@assert codomain(a) === X
@assert codomain(b) === Y
@check compose(a, f) == compose(b, g) "maps do not commute"
@check compose(ff, g) == compose(gg, f) "maps do not commute"
return _induced_map_to_fiber_product(a, b, f, g, fiber_product=fiber_product, check=check)
end

function _induced_map_to_fiber_product(
a::AbsSpecMor, b::AbsSpecMor,
f::AbsSpecMor, g::AbsSpecMor;
fiber_product::Tuple{<:AbsSpec, <:AbsSpecMor, <:AbsSpecMor}=fiber_product(f, g),
check::Bool=true
)
# The ambient scheme of XxY is the actual product of X and Y
# over Spec(k), the coefficient ring. If it is not, then
# this is due to special dispatch which has to also be caught
# with a special method for this function here.
XxY = fiber_product[1]
gg = fiber_product[2]
ff = fiber_product[3]
X = domain(f)
Y = domain(g)
W = domain(a)
@check gens(OO(XxY)) == vcat(pullback(gg).(gens(OO(X))), pullback(ff).(gens(OO(Y)))) "variables must be pullbacks of variables on the factors"

img_gens = vcat(pullback(a).(gens(OO(X))), pullback(b).(gens(OO(Y))))
return SpecMor(W, XxY, img_gens, check=check)
end

# When the fiber product was created from at least one `PrincipalOpenEmbedding`,
# then the construction did not proceed via the `product` of `X` and `Y`.
# In this case, the induced map must be created differently.
function _induced_map_to_fiber_product(
a::AbsSpecMor, b::AbsSpecMor,
f::PrincipalOpenEmbedding, g::AbsSpecMor;
fiber_product::Tuple{<:AbsSpec, <:AbsSpecMor, <:PrincipalOpenEmbedding}=fiber_product(f, g),
check::Bool=true
)
# XxY is a principal open subset of Y.
XxY = fiber_product[1]
W = domain(a)
Y = codomain(b)
img_gens = pullback(b).(gens(OO(Y)))
return SpecMor(W, XxY, img_gens, check=check)
end

function _induced_map_to_fiber_product(
a::AbsSpecMor, b::AbsSpecMor,
f::AbsSpecMor, g::PrincipalOpenEmbedding;
fiber_product::Tuple{<:AbsSpec, <:PrincipalOpenEmbedding, <:AbsSpecMor}=fiber_product(f, g),
check::Bool=true
)
# XxY is a principal open subset of X.
XxY = fiber_product[1]
X = domain(f)
W = domain(a)
img_gens = pullback(a).(gens(OO(X)))
return SpecMor(W, XxY, img_gens, check=check)
end

# additional method to remove ambiguity
function _induced_map_to_fiber_product(
a::AbsSpecMor, b::AbsSpecMor,
f::PrincipalOpenEmbedding, g::PrincipalOpenEmbedding;
fiber_product::Tuple{<:AbsSpec, <:PrincipalOpenEmbedding, <:PrincipalOpenEmbedding}=fiber_product(f, g),
check::Bool=true
)
W = domain(a)
# XxY is a principal open subset of Y.
XxY = fiber_product[1]
Y = domain(g)
img_gens = pullback(b).(gens(OO(Y)))
return SpecMor(W, XxY, img_gens, check=check)
end

### Some helper functions
function _restrict_domain(f::AbsSpecMor, D::PrincipalOpenSubset; check::Bool=true)
D === domain(f) && return f
ambient_scheme(D) === domain(f) && return SpecMor(D, codomain(f), OO(D).(pullback(f).(gens(OO(codomain(f))))), check=false)
@check is_subset(D, domain(f)) "domain incompatible"
return SpecMor(D, codomain(f), OO(D).(pullback(f).(gens(OO(codomain(f))))), check=check)
end

function _restrict_domain(f::AbsSpecMor, D::AbsSpec; check::Bool=true)
D === domain(f) && return f
@check is_subset(D, domain(f)) "domain incompatible"
return SpecMor(D, codomain(f), OO(D).(pullback(f).(gens(OO(codomain(f))))), check=check)
end

function _restrict_codomain(f::AbsSpecMor, D::PrincipalOpenSubset; check::Bool=true)
D === codomain(f) && return f
if ambient_scheme(D) === codomain(f)
@check is_unit(pullback(f)(complement_equation(D))) "complement equation does not pull back to a unit"
return SpecMor(domain(f), D, OO(domain(f)).(pullback(f).(gens(OO(codomain(f))))), check=false)
end
@check is_subset(D, codomain(f)) "codomain incompatible"
@check is_subset(domain(f), preimage(f, D))
return SpecMor(domain(f), D, OO(domain(f)).(pullback(f).(gens(OO(codomain(f))))), check=check)
end

function _restrict_codomain(f::AbsSpecMor, D::AbsSpec; check::Bool=true)
@check is_subset(D, codomain(f)) "codomain incompatible"
@check is_subset(domain(f), preimage(f, D))
return SpecMor(domain(f), D, OO(domain(f)).(pullback(f).(gens(OO(codomain(f))))), check=check)
end

function restrict(f::AbsSpecMor, D::AbsSpec, Z::AbsSpec; check::Bool=true)
interm = _restrict_domain(f, D; check)
return _restrict_codomain(interm, Z; check)
end

function Base.:(==)(f::AbsSpecMor, g::AbsSpecMor)
domain(f) === domain(g) || return false
codomain(f) === codomain(g) || return false
return pullback(f) == pullback(g)
end

###########################################################
# (2) The direct product of two affine schemes
Expand Down Expand Up @@ -214,10 +417,9 @@ and a ring homomorphism ``φ : 𝕜 → 𝕂`` this returns a triple
↑ b₁ ↑ b₂
X×ₖSpec(𝕂) → Y×ₖSpec(𝕂)
F
```
The optional arguments `domain_map` and `codomain_map` can be used
to specify the morphisms `b₁` and `b₂`, respectively.
```
"""
function base_change(phi::Any, f::AbsSpecMor;
domain_map::AbsSpecMor=base_change(phi, domain(f))[2],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,15 @@ function subscheme(X::AbsSpec, I::Ideal)
return Y
end

function sub(X::AbsSpec, a)
(a isa RingElem && parent(a) === OO(X)) || return sub(X, OO(X)(a))
return sub(X, ideal(OO(X), a))
end

function sub(X::AbsSpec, a::Vector)
all(a->a isa RingElem && parent(a) === OO(X), a) || return sub(X, OO(X).(a))
return sub(X, ideal(OO(X), a))
end


########################################################
Expand Down
Loading

0 comments on commit 448c2f9

Please sign in to comment.