Skip to content

Commit

Permalink
Intersect. theory: Further clean up (#4188)
Browse files Browse the repository at this point in the history
* Intersect. theory: Further clean up

* Independently, correct docstring for `èxterior_algebra`
  • Loading branch information
wdecker authored Oct 9, 2024
1 parent 43bf5e0 commit c146706
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 93 deletions.
4 changes: 2 additions & 2 deletions experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export exterior_algebra
exterior_algebra(K::Ring, varnames::AbstractVector{<:VarName})
Given a coefficient ring `K` and variable names, say `varnames = [:x1, :x2, ...]`,
return a tuple `E, [x1, x2, ...] of the exterior algebra `E` over
the polynomial ring `R[x1, x2, \dots]``, and its generators `x1, x2, \dots`.
return a tuple `E, [x1, x2, ...]` consisting of the exterior algebra `E` over
the polynomial ring `R[x1, x2, ...]` and its generators `x1, x2, ...`.
If `K` is a field, this function will use a special implementation in Singular.
Expand Down
55 changes: 42 additions & 13 deletions experimental/IntersectionTheory/src/Main.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ Then, we show the constructor above at work.
julia> P4 = abstract_projective_space(4)
AbstractVariety of dim 4
julia> A = 5*line_bundle(P4, 2)
julia> A = 5*OO(P4, 2)
AbstractBundle of rank 5 on AbstractVariety of dim 4
julia> B = 2*exterior_power(cotangent_bundle(P4), 2)*OO(P4, 5)
AbstractBundle of rank 12 on AbstractVariety of dim 4
julia> C = 5*line_bundle(P4, 3)
julia> C = 5*OO(P4, 3)
AbstractBundle of rank 5 on AbstractVariety of dim 4
julia> F = B-A-C
Expand Down Expand Up @@ -230,6 +230,25 @@ In case of an inclusion $i:X\hookrightarrow Y$ where the class of `X` is not
present in the Chow ring of `Y`, use the argument `inclusion = true`. Then,
a copy of `Y` will be created, with extra classes added so that one can
pushforward all classes on `X`.
# Examples
```jldoctest
julia> P2xP2 = abstract_projective_space(2, symbol = "k")*abstract_projective_space(2, symbol = "l")
AbstractVariety of dim 4
julia> P8 = abstract_projective_space(8)
AbstractVariety of dim 8
julia> k, l = gens(P2xP2)
2-element Vector{MPolyQuoRingElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
k
l
julia> Se = hom(P2xP2, P8, [k+l]) # Segre embedding
AbstractVarietyMap from AbstractVariety of dim 4 to AbstractVariety of dim 8
```
"""
function hom(X::AbstractVariety, Y::AbstractVariety, fˣ::Vector, fₓ = nothing; inclusion::Bool = false, symbol::String = "x")
AbstractVarietyMap(X, Y, fˣ, fₓ)
Expand Down Expand Up @@ -1063,8 +1082,8 @@ end
Return the product $X\times Y$. Alternatively, use `*`.
!!!note
If both `X` and `Y` have a hyperplane class, $X\times Y$ will be endowed with the hyperplane class corresponding to the Segre embedding.
!!! note
If both `X` and `Y` have a hyperplane class, $X\times Y$ will be endowed with the hyperplane class corresponding to the Segre embedding.
```jldoctest
julia> P2 = abstract_projective_space(2);
Expand Down Expand Up @@ -1188,6 +1207,7 @@ end
-(F::AbstractBundle)
*(n::RingElement, F::AbstractBundle)
+(F::AbstractBundle, G::AbstractBundle)
-(F::AbstractBundle, G::AbstractBundle)
*(F::AbstractBundle, G::AbstractBundle)
Return `-F`, the sum `F` $+ \dots +$ `F` of `n` copies of `F`, `F` $+$ `G`, `F` $-$ `G`, and the tensor product of `F` and `G`, respectively.
Expand Down Expand Up @@ -1412,7 +1432,7 @@ Given an element `x` of the Chow ring of an abstract variety `X`, say, return th
!!! note
If `X` has a (unique) point class, the integral will be a
number (that is, a `QQFieldElem` or a function field element). Otherwise, the highests degree part of $x$ is returned
number (that is, a `QQFieldElem` or a function field element). Otherwise, the highest degree part of $x$ is returned
(geometrically, this is the 0-dimensional part of $x$).
# Examples
Expand Down Expand Up @@ -1443,7 +1463,7 @@ end
@doc raw"""
intersection_matrix(X::AbstractVariety)
If `b = basis(X)`, return `matrix([integral(bi*bj) for bi in b, bj in b])`.
If `b = vcat(basis(X)...)`, return `matrix([integral(bi*bj) for bi in b, bj in b])`.
intersection_matrix(a::Vector, b::Vector)
Expand All @@ -1458,14 +1478,23 @@ As above, with `b = a`.
julia> G = abstract_grassmannian(2,4)
AbstractVariety of dim 4
julia> b = basis(G)
julia> basis(G)
5-element Vector{Vector{MPolyQuoRingElem}}:
[1]
[c[1]]
[c[2], c[1]^2]
[c[1]*c[2]]
[c[2]^2]
julia> b = vcat(basis(G)...)
6-element Vector{MPolyQuoRingElem}:
1
c[1]
c[2]
c[1]^2
c[1]*c[2]
c[2]^2
julia> intersection_matrix(G)
[0 0 0 0 0 1]
[0 0 0 0 1 0]
Expand All @@ -1474,7 +1503,7 @@ julia> intersection_matrix(G)
[0 1 0 0 0 0]
[1 0 0 0 0 0]
julia> integral(b[3][2]*b[3][2])
julia> integral(b[4]*b[4])
2
```
Expand Down Expand Up @@ -2018,17 +2047,17 @@ Quotient
h -> [1]
by ideal (h^3, z^2 + 3*z*h + 3*h^2)
julia> [chern_class(T, i) for i = 1:2]
2-element Vector{MPolyQuoRingElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
3*h
3*h^2
julia> gens(PT)[1]
z
julia> gens(PT)[1] == hyperplane_class(PT)
true
julia> [chern_class(T, i) for i = 1:2]
2-element Vector{MPolyQuoRingElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
3*h
3*h^2
```
```jldoctest
Expand Down
175 changes: 97 additions & 78 deletions experimental/IntersectionTheory/src/blowup.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ julia> sect(s)
```
```
```jldoctest
julia> A, (a, b, c) = polynomial_ring(QQ, [:a, :b, :c]);
julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
Expand Down Expand Up @@ -195,12 +195,12 @@ function present_finite_extension_ring(F::Oscar.AffAlgHom)
V = groebner_basis(J)

sect = x -> (y = reduce(BRtoR(x), gens(V));
ans = elem_type(AR)[];
for i in 1:g
q = div(y, gs_lift[i])
push!(ans, RtoAR(q))
y -= q * gs_lift[i]
end; ans)
ans = elem_type(AR)[];
for i in 1:g
q = div(y, gs_lift[i])
push!(ans, RtoAR(q))
y -= q * gs_lift[i]
end; ans)

FM = free_module(R, g)
gB = elem_type(FM)[FM(push!([j == i ? R(1) : R() for j in 1:g-1], -gs_lift[i])) for i in 1:g-1]
Expand Down Expand Up @@ -266,123 +266,142 @@ function blowup(i::AbstractVarietyMap; symbol::String = "e")
# | |
# g f
# | |
# X ---i---> Y
# Z ---i---> X

SED = symbol # SED = "e"
X, Y = i.domain, i.codomain
AY, RY = Y.ring, base_ring(Y.ring)
Z, X = i.domain, i.codomain
AZ, RZ = Z.ring, base_ring(Z.ring)
AX, RX = X.ring, base_ring(X.ring)

# we write N for the normal bundle N_{ZX}

# we will write N for the normal bundle N_{XY}
# and construct E as the projective bundle PN later in the code
N = -i.T # normal bundle
rN = rank(N) # codimension of X in Y
rN = rank(N) # codimension of Z in X
rN <= 0 && error("not a proper subvariety")

gs, PM, sect = present_finite_extension_ring(i.pullback)
ngs = length(gs)
# note: gs is a vector of polynomials representing generators for AX as an AY-module;
# write X(gs[i]) for the class in AX represented by gs[i];
# if E[i] = jₓgˣ(X(gs[i])), then E[end] is the class of the exceptional divisor in ABl;
# here, present_finite_extension_ring needs to return the generators accordingly;
# that is, X(gs[end]) must by the generator 1_{AX};
# we will write ζ for the first Chern class of O_PN(1);
# note: ζ = -jˣ(E[end])
# we construct E as the projective bundle PN of N, see [E-H, p 472]

E = abstract_projective_bundle(N)
AE, RE = E.ring, base_ring(E.ring)
g = E.struct_map
ζ = g.O1 # the first Chern class of O_PN(1)
### Q = E.bundles[2] # the universal quotient bundle on PN
### ctopQ = top_chern_class(Q)

# we set up the generators of ABl

# by E-H, Prop. 13.12, ABl is generated by jₓ(AE) and fˣ(AY) as a K-algebra
# Equivalently, as an AY-algebra, ABl is generated by the E[i];
syms = vcat(push!(_parse_symbol(SED, 1:ngs-1), SED), string.(gens(RY)))
degs = [degree(Int, X(gs[i])) + 1 for i in 1:ngs]
degsRY = [Int(degree(gens(RY)[i])[1]) for i = 1:ngens(RY)]
RBl = graded_polynomial_ring(Y.base, syms, vcat(degs, degsRY))[1]
# we first represent AZ as an AX-module

gs, PM, sect = present_finite_extension_ring(i.pullback)
ngs = length(gs)
# note: gs is a vector of polynomials representing generators for AZ as an AX-module;
# write Z(gs[i]) for the class in AZ represented by gs[i];
# if e[i] = jₓgˣ(Z(gs[i])), then e[end] is the class of the exceptional divisor in ABl;
# here, present_finite_extension_ring needs to return the generators accordingly;
# that is, Z(gs[end]) must by the generator 1_{AZ}; note that ζ = -jˣ(e[end]).

# by E-H, Prop. 13.12, ABl is generated by jₓ(AE) and fˣ(AX) as a K-algebra;
# equivalently, as an AX-algebra, ABl is generated by the e[i].
syms = vcat(push!(_parse_symbol(SED, 1:ngs-1), SED), string.(gens(RX))) # set e = e[end]
degs = [degree(Int, Z(gs[i])) + 1 for i in 1:ngs]
degsRX = [Int(degree(gens(RX)[i])[1]) for i = 1:ngens(RX)]
RBl = graded_polynomial_ring(X.base, syms, vcat(degs, degsRX))[1]

E, y = gens(RBl)[1:ngs], gens(RBl)[ngs+1:end]
= hom(RY, RBl, y)
jₓgˣ = x -> sum(E .* .(sect(x.f)))
ev, xv = gens(RBl)[1:ngs], gens(RBl)[ngs+1:end]
RXtoRBl = hom(RX, RBl, xv) # fˣ on polynomial ring level
jₓgˣ = x -> sum(ev .* RXtoRBl.(sect(x.f))) # AZ --> RBl

# we set up the relations of ABl

Rels = elem_type(RBl)[]

# 1) relations from Y
if isdefined(AY, :I)
for r in .(gens(AY.I)) push!(Rels, r) end
# 1) relations from AX

if isdefined(AX, :I)
for r in RXtoRBl.(gens(AX.I)) push!(Rels, r) end
end

# 2) relations for AˣX as an AˣY-module
### for r in transpose(E) * fˣ.(PM) push!(Rels, r) end
for r in .(PM)*E push!(Rels, r) end
# 2) relations for AZ as an AX-module

for r in RXtoRBl.(PM)*ev push!(Rels, r) end

# 3) relation from AE: ∑ gˣcₖ(N) ⋅ ζᵈ⁻ᵏ = 0, see EH Thm. 9.6

# 3) relation from AˣPN: ∑ gˣcₖ(N) ⋅ ζᵈ⁻ᵏ = 0, see EH Thm. 9.6
cN = total_chern_class(N)[0:rN] # cN[k] = cₖ₋₁(N)
push!(Rels, sum([jₓgˣ(cN[k+1]) * (-E[end])^(rN-k) for k in 0:rN]))
cN = total_chern_class(N)[0:rN] # cN[k] = c_k ₋₁(N)
push!(Rels, sum([jₓgˣ(cN[k+1]) * (-ev[end])^(rN-k) for k in 0:rN]))

# 4) jₓx ⋅ jₓy = -jₓ(x⋅y⋅ζ) # rule for multiplication, EH, Prop. 13.12
# recall that E[i] = jₓgˣ(X(gs[i]))
# recall that e[i] = jₓgˣ(Z(gs[i]))

for j in 1:ngs-1, k in j:ngs-1
push!(Rels, E[j] * E[k] + jₓgˣ(X(gs[j] * gs[k])) * (-E[end]))
push!(Rels, ev[j] * ev[k] + jₓgˣ(Z(gs[j] * Z(gs[k]))) * (-ev[end]))
end

# 5) fˣiₓx = jₓ(gˣx ⋅ ctop(Q)) where Q is the tautological quotient bundle on PN
# 5) relation as in the proof of [E-H], Theorem 13.14:
# RXtoRBliₓx = jₓ(gˣx ⋅ ctop(Q)) where Q is the tautological quotient bundle on E
# we have ctop(Q) = ∑ gˣcₖ₋₁(N) ⋅ ζᵈ⁻ᵏ, EH p. 477

for j in 1:ngs
lhs = (i.pushforward(X(gs[j])).f) # this is the crucial step where iₓ is needed
### rhs = sum([jₓgˣ(gs[j] * cN[k]) * (-E[end])^(rN-k) for k in 1:rN])
rhs = sum([jₓgˣ(X(gs[j]) * cN[k]) * (-E[end])^(rN-k) for k in 1:rN])
lhs = RXtoRBl(i.pushforward(Z(gs[j])).f) # this is the crucial step where iₓ is needed
rhs = sum([jₓgˣ(Z(gs[j]) * cN[k]) * (-ev[end])^(rN-k) for k in 1:rN])
push!(Rels, lhs - rhs)
end

Rels = minimal_generating_set(ideal(RBl, Rels)) ### TODO: make this an option?
AˣBl, _ = quo(RBl, Rels)
Bl = abstract_variety(Y.dim, AˣBl)
ABl, _ = quo(RBl, Rels)
Bl = abstract_variety(X.dim, ABl)

# Bl and g being constructed, we set up the morphisms f and j

# Bl being constructed, we set up the morphisms f, g, and j
# pushforward of f and more

RBltoRY = hom(RBl, RY, vcat(repeat([RY()], ngs), gens(RY)))
RBltoRX = hom(RBl, RX, vcat(repeat([RX()], ngs), gens(RX)))
fₓ = x -> (xf = simplify(x).f;
Y(RBltoRY(xf));)
fₓ = map_from_func(fₓ, Bl.ring, Y.ring)
f = AbstractVarietyMap(Bl, Y, Bl.(y), fₓ)
X(RBltoRX(xf));)
fₓ = map_from_func(fₓ, ABl, AX)
f = AbstractVarietyMap(Bl, X, Bl.(xv), fₓ)
Bl.struct_map = f
if isdefined(Y, :point) Bl.point = f.pullback(Y.point) end
PN = abstract_projective_bundle(N) # the exceptional divisor as the projectivization of N
if isdefined(X, :point) Bl.point = f.pullback(X.point) end

# pullback of j

g = PN.struct_map
ζ = g.O1
= vcat([-ζ * g.pullback(X(xi)) for xi in gs], [g.pullback(i.pullback(f)) for f in gens(AY)])
= vcat([-ζ * g.pullback(Z(xi)) for xi in gs], [g.pullback(i.pullback(f)) for f in gens(AX)])

# pushforward of j: write as a polynomial in ζ, and compute term by term
RX = base_ring(X.ring)
RPNtoRX = hom(base_ring(PN.ring), RX, pushfirst!(gens(RX), RX()))

REtoRZ = hom(RE, RZ, pushfirst!(gens(RZ), RZ()))
jₓ = x -> (xf = simplify(x).f;
RX = base_ring(X.ring); ans = RBl();
for k in rN-1:-1:0
q = div(xf, ζ.f^k)
ans += jₓgˣ(X(RPNtoRX(q))) * (-E[end])^k
xf -= q * ζ.f^k
end; Bl(ans))
jₓ = map_from_func(jₓ, PN.ring, Bl.ring)
j = AbstractVarietyMap(PN, Bl, jˣ, jₓ)
ans = RBl();
for k in rN-1:-1:0
q = div(xf, ζ.f^k)
ans += jₓgˣ(Z(REtoRZ(q))) * (-ev[end])^k
xf -= q * ζ.f^k
end;
Bl(ans))
jₓ = map_from_func(jₓ, AE, AX)
j = AbstractVarietyMap(E, Bl, jˣ, jₓ)

# the normal bundle of E in Bl is O(-1)
j.T = -PN.bundles[1]

j.T = -E.bundles[1]

# finally, compute the tangent bundle of Bl
# 0 → Bl.T → fˣ(Y.T) → jₓ(Q) → 0 where Q is the tautological quotient bundle
f.T = -pushforward(j, PN.bundles[2])
Bl.T = pullback(f, Y.T) + f.T

# 0 → Bl.T → RXtoRBl(X.T) → jₓ(Q) → 0 where Q is the tautological quotient bundle

f.T = -pushforward(j, E.bundles[2])
Bl.T = pullback(f, X.T) + f.T

# chern(Bl.T) can be readily computed from its Chern character, but the following is faster
α = sum(sum((binomial(ZZ(rN-j), ZZ(k)) - binomial(ZZ(rN-j), ZZ(k+1))) * ζ^k for k in 0:rN-j) * g.pullback(chern_class(N, j)) for j in 0:rN)
Bl.T.chern = simplify(f.pullback(total_chern_class(Y.T)) + j.pushforward(g.pullback(total_chern_class(X.T)) * α))
set_attribute!(PN, :projections => [j, g])
set_attribute!(Bl, :exceptional_divisor => PN)
set_attribute!(Bl, :description => "Blowup of $Y with center $X")
if get_attribute(X, :alg) == true && get_attribute(Y, :alg) == true
Bl.T.chern = simplify(f.pullback(total_chern_class(X.T)) + j.pushforward(g.pullback(total_chern_class(Z.T)) * α))
set_attribute!(E, :projections => [j, g])
set_attribute!(Bl, :exceptional_divisor => E)
set_attribute!(Bl, :description => "Blowup of $X with center $Z")
if get_attribute(Z, :alg) == true && get_attribute(X, :alg) == true
set_attribute!(Bl, :alg => true)
end
return Bl, PN, j
return Bl, E, j
end


Expand Down

0 comments on commit c146706

Please sign in to comment.