From 13cbc1408f56d19694fd206279c7911f63aedea5 Mon Sep 17 00:00:00 2001 From: Wolfram Decker Date: Mon, 7 Oct 2024 13:06:35 +0200 Subject: [PATCH] Intersect. Theory: Code cleanup, correction, new example --- .../IntersectionTheory/docs/src/intro.md | 14 +- experimental/IntersectionTheory/src/Main.jl | 15 +- experimental/IntersectionTheory/src/blowup.jl | 267 +++++++++++------- .../IntersectionTheory/test/runtests.jl | 10 +- 4 files changed, 185 insertions(+), 121 deletions(-) diff --git a/experimental/IntersectionTheory/docs/src/intro.md b/experimental/IntersectionTheory/docs/src/intro.md index c8500db1be2d..06b0e7cca9d2 100644 --- a/experimental/IntersectionTheory/docs/src/intro.md +++ b/experimental/IntersectionTheory/docs/src/intro.md @@ -6,12 +6,18 @@ CurrentModule = Oscar In this chapter, we - introduce OSCAR tools which support computations in intersection theory, and -- give examples which illustrate how intersection theory is used to -solve problems from enumerative geometry. +- give examples which illustrate how intersection theory is used to solve problems from enumerative geometry. !!! note - Making use of OSCAR, a first version of what we present here was - written by Jeiao Song as a julia package. + Making use of OSCAR, a first version of what we present here was written by Jeiao Song as a julia package. + This package was "heavily inspired by the Macaulay2 package Schubert2 and the Sage library Chow. Some + functionalities from [the Sage library] Schubert3 are also implemented." + +!!! note + Schubert2 was written by Daniel R. Grayson, Michael E. Stillman, Stein A. Strømme, David Eisenbud, and Charley Crissman + while Chow is due to Manfred Lehn and Christoph Sorger. Schubert3 as well as the Singular library schubert.lib were + written by Dang Tuan Hiep. The basis for all this work, including ours, is the Maple package Schubert written + by Sheldon Katz and Stein A. Strømme. Throughout the chapter, the varieties we consider are smooth projective varieties over the complex numbers. diff --git a/experimental/IntersectionTheory/src/Main.jl b/experimental/IntersectionTheory/src/Main.jl index 64b0c7711b49..d9f39b2c81c9 100644 --- a/experimental/IntersectionTheory/src/Main.jl +++ b/experimental/IntersectionTheory/src/Main.jl @@ -1295,7 +1295,7 @@ function schur_functor(F::AbstractBundle, λ::Partition) λ = conjugate(λ) X = F.parent w = _wedge(sum(λ), chern_character(F)) - S, ei = polynomial_ring(QQ, "e#" => 1:length(w)) + S, ei = polynomial_ring(QQ, ["e$i" for i in 1:length(w)]) e = i -> i < 0 ? S() : ei[i+1] M = [e(λ[i]-i+j) for i in 1:length(λ), j in 1:length(λ)] sch = det(matrix(S, M)) # Jacobi-Trudi @@ -1373,18 +1373,19 @@ Return an additive basis of the Chow ring of `X` in codimension `k`. basis(X::AbstractVariety, k::Int) = basis(X)[k+1] @doc raw""" - betti(X::AbstractVariety) + betti_numbers(X::AbstractVariety) -Return the Betti numbers of the Chow ring of `X`. Note that these are not -necessarily equal to the usual Betti numbers, i.e., the dimensions of -(co)homologies. +Return the Betti numbers of the Chow ring of `X`. + +!!! note + The Betti number of `X` in a given degree is the number of elements of `basis(X)` in that degree. # Examples ```jldoctest julia> P2xP2 = abstract_projective_space(2, symbol = "k")*abstract_projective_space(2, symbol = "l") AbstractVariety of dim 4 -julia> betti(P2xP2) +julia> betti_numbers(P2xP2) 5-element Vector{Int64}: 1 2 @@ -1402,7 +1403,7 @@ julia> basis(P2xP2) ``` """ -betti(X::AbstractVariety) = length.(basis(X)) +betti_numbers(X::AbstractVariety) = length.(basis(X)) @doc raw""" integral(x::MPolyDecRingElem) diff --git a/experimental/IntersectionTheory/src/blowup.jl b/experimental/IntersectionTheory/src/blowup.jl index 529108316f78..3b9289ae14e8 100644 --- a/experimental/IntersectionTheory/src/blowup.jl +++ b/experimental/IntersectionTheory/src/blowup.jl @@ -14,26 +14,64 @@ $A^r \rightarrow A^s\rightarrow B \rightarrow 0$ of `B` as an `A`-module. -More precisely, return a tuple `(gensB, M, pf)`, say, where -- `gensB` is a vector of polynomials representing generators for `B` as an `A`-module, -- `M` is an `r` $\times$ `s`-matrix of polynomials defining the map $A^r \rightarrow A^s$, and -- `pf` is a map which gives rise to a section of the map $ A^s\rightarrow B$. +More precisely, return a tuple `(gs, PM, sect)`, say, where +- `gs` is a vector of polynomials representing generators for `B` as an `A`-module, +- `PM` is an `r` $\times$ `s`-matrix of polynomials defining the map $A^r \rightarrow A^s$, and +- `sect` is a function which gives rise to a section of the augmentation map $ A^s\rightarrow B$. !!! note The finiteness condition on `F` is checked by the function. +!!! note + The function is implemented so that the last element of `gs` is `one(B)`. + # Examples +``` +julia> RA, (h,) = polynomial_ring(QQ, [:h]); + +julia> A, _ = quo(RA, ideal(RA, [h^9])); + +julia> RB, (k, l) = polynomial_ring(QQ, [:k, :l]); + +julia> B, _ = quo(RB, ideal(RB, [k^3, l^3])); + +julia> F = hom(A, B, [k+l]) +Ring homomorphism + from quotient of multivariate polynomial ring by ideal (h^9) + to quotient of multivariate polynomial ring by ideal (k^3, l^3) +defined by + h -> k + l + +julia> gs, PM, sect = present_finite_extension_ring(F); + +julia> gs +3-element Vector{QQMPolyRingElem}: + l^2 + l + 1 + +julia> PM +3×3 Matrix{QQMPolyRingElem}: + h^3 0 0 + -3*h^2 h^3 0 + 3*h -3*h^2 h^3 + +julia> sect(k*l) +3-element Vector{QQMPolyRingElem}: + -1 + h + 0 + +``` + ```jldoctest julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]); -julia> I = ideal(R, [z^2-y^2*(y+1)]) -Ideal generated by - -y^3 - y^2 + z^2 +julia> I = ideal(R, [z^2-y^2*(y+1)]); -julia> A, _ = quo(R, I) -(Quotient of multivariate polynomial ring by ideal (-y^3 - y^2 + z^2), Map: R -> A) +julia> A, _ = quo(R, I); -julia> B, (s,t) = polynomial_ring(QQ, [:s, :t]); +julia> B, (s,t) = polynomial_ring(QQ, ["s", "t"]); julia> F = hom(A,B, [s, t^2-1, t*(t^2-1)]) Ring homomorphism @@ -44,27 +82,32 @@ defined by y -> t^2 - 1 z -> t^3 - t -julia> gensB, M, pf = present_finite_extension_ring(F); +julia> gs, PM, sect = present_finite_extension_ring(F); -julia> gensB +julia> gs 2-element Vector{QQMPolyRingElem}: t 1 -julia> M +julia> PM 2×2 Matrix{QQMPolyRingElem}: y -z -z y^2 + y -julia> pf(s) +julia> sect(t) 2-element Vector{QQMPolyRingElem}: + 1 0 - x -julia> pf(t) +julia> sect(one(B)) 2-element Vector{QQMPolyRingElem}: + 0 1 + +julia> sect(s) +2-element Vector{QQMPolyRingElem}: 0 + x ``` @@ -73,18 +116,11 @@ julia> A, (a, b, c) = polynomial_ring(QQ, [:a, :b, :c]); julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]); -julia> I = ideal(R, [x*y]) -Ideal generated by - x*y +julia> I = ideal(R, [x*y]); -julia> B, _ = quo(R, I) -(Quotient of multivariate polynomial ring by ideal (x*y), Map: R -> B) +julia> B, _ = quo(R, I); -julia> (x, y, z) = gens(B) -3-element Vector{MPolyQuoRingElem{QQMPolyRingElem}}: - x - y - z +julia> (x, y, z) = gens(B); julia> F = hom(A, B, [x^2+z, y^2-1, z^3]) Ring homomorphism @@ -95,24 +131,24 @@ defined by b -> y^2 - 1 c -> z^3 -julia> gensB, M, pf = present_finite_extension_ring(F); +julia> gs, PM, sect = present_finite_extension_ring(F); -julia> gensB +julia> gs 2-element Vector{QQMPolyRingElem}: y 1 -julia> M +julia> PM 2×2 Matrix{QQMPolyRingElem}: a^3 - c 0 0 a^3*b + a^3 - b*c - c -julia> pf(y) +julia> sect(y) 2-element Vector{QQMPolyRingElem}: 1 0 -julia> pf(one(B)) +julia> sect(one(B)) 2-element Vector{QQMPolyRingElem}: 0 1 @@ -121,6 +157,7 @@ julia> pf(one(B)) """ function present_finite_extension_ring(F::Oscar.AffAlgHom) A, B = F.domain, F.codomain + a, b = ngens(A), ngens(B) if A isa MPolyQuoRing AR = base_ring(A) @@ -129,58 +166,53 @@ function present_finite_extension_ring(F::Oscar.AffAlgHom) end if B isa MPolyQuoRing BR = base_ring(B) - M = [F(gens(A)[i]).f for i = 1:ngens(A)] + M = [F(gens(A)[i]).f for i = 1:a] else BR = B - M = [F(gens(A)[i]) for i = 1:ngens(A)] + M = [F(gens(A)[i]) for i = 1:a] end + @assert base_ring(AR) == base_ring(BR) I = ideal(BR, isdefined(B, :I) ? vcat(gens(B.I), M) : M) C, _ = quo(BR, I) - gensB = monomial_basis(C) - @assert gensB[end] == 1 # the last one should always be 1 - g = length(gensB) + gs = monomial_basis(C) # monomials whose residue classes form a K-basis of B + @assert gs[end] == 1 # the last one should always be 1 + g = length(gs) - base = base_ring(AR) - symsA, symsB = string.(gens(AR)), string.(gens(BR)) - a, b = length(symsA), length(symsB) R, _ = tensor_product(BR, AR, use_product_ordering = true) ba = gens(R) - - AtoR = hom(AR, R, ba[b+1:end], check = false) - BtoR = hom(BR, R, ba[1:b], check = false) - RtoA = hom(R, AR, vcat(repeat([AR()], b), gens(AR))) - - gensB_lift = [R(BtoR(g)) for g in gensB] + ARtoR = hom(AR, R, ba[b+1:end], check = false) + BRtoR = hom(BR, R, ba[1:b], check = false) + RtoAR = hom(R, AR, vcat(repeat([AR()], b), gens(AR))) + gs_lift = [BRtoR(g) for g in gs] # compute the ideal J of the graph of F - rels = [R(ba[b+i]-BtoR(m)) for (i,m) in enumerate(M)] - if isdefined(A, :I) for g in gens(A.I) push!(rels, R(AtoR(g))) end end - if isdefined(B, :I) for g in gens(B.I) push!(rels, R(BtoR(g))) end end - J = ideal(R, rels) # the ideal of the graph of F - + Rels = [ba[b+i]-BRtoR(m) for (i,m) in enumerate(M)] + if isdefined(A, :I) for g in gens(A.I) push!(Rels, ARtoR(g)) end end + if isdefined(B, :I) for g in gens(B.I) push!(Rels, BRtoR(g)) end end + J = ideal(R, Rels) # the ideal of the graph of F V = groebner_basis(J) - pf = x -> (y = reduce(R(BtoR(BR(x))), gens(V)); - ans = Nemo.elem_type(AR)[]; - for i in 1:g - q = div(y, gensB_lift[i]) - push!(ans, RtoA(q)) - y -= q * gensB_lift[i] - end; ans) + + 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) FM = free_module(R, g) - gB = elem_type(FM)[FM(push!([j == i ? R(1) : R() for j in 1:g-1], -gensB_lift[i])) for i in 1:g-1] - gJ = elem_type(FM)[FM([j==i ? x : R() for j in 1:g]) for x in gens(J) for i in 1: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] + gJ = elem_type(FM)[FM([j==i ? x : R() for j in 1:g]) for x in gens(V) for i in 1:g] U = vcat(gB, gJ) S, _ = sub(FM, U) P = groebner_basis(S, ordering = default_ordering(R)*lex(FM)) Rw, _ = grade(R, vcat(repeat([1], b), repeat([0], a))) RtoRw = hom(R, Rw, gens(Rw)) inA = x -> x == zero(Rw) ? true : (degree(Int, leading_term(RtoRw(x)))) <= 0 - M = hcat([(RtoA.(Vector(P[i]))) for i in 1:ngens(P) if all(inA, Vector(P[i]))]...) - - return gensB, M, pf + PM = vcat([(RtoAR.(transpose(Vector(P[i])))) for i in 1:ngens(P) if all(inA, Vector(P[i]))]...) + return gs, PM, sect end ###################################### @@ -195,7 +227,7 @@ More precisely, return a tuple `(Bl, E, j)`, say, where - `j`, a map of abstract varieties, is the inclusion of `E` into `Bl`. !!! note - The resulting maps `Bl` $\rightarrow$ `Y` and `E` $\rightarrow$ `X` are obtained entering `structure_map(E)` and `structure_map(Bl)`, respectively. + The resulting maps `Bl` $\rightarrow$ `Y` and `E` $\rightarrow$ `X` are obtained entering `structure_map(Bl)` and `structure_map(E)`, respectively. # Examples @@ -229,60 +261,85 @@ julia> integral((6*HBl-2*e)^5) ``` """ function blowup(i::AbstractVarietyMap; symbol::String = "e") - SED = symbol + # use construction via generators and relations as in Eisenbud-Harris, Section 13.6 + # E ---j---> Bl + # | | + # g f + # | | + # X ---i---> Y + + SED = symbol # SED = "e" X, Y = i.domain, i.codomain + AY, RY = Y.ring, base_ring(Y.ring) + + # 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 - d = rank(N) # codimension of X in Y - d <= 0 && error("not a proper subvariety") - AˣY, RY = Y.ring, base_ring(Y.ring) - gs, M, pf = present_finite_extension_ring(i.pullback) - n = length(gs) - - # the last variable E is the class of the exceptional divisor - syms = vcat(push!(_parse_symbol(SED, 1:n-1), SED), string.(gens(RY))) - degs = [degree(Int, X(gs[i])) + 1 for i in 1:n] + rN = rank(N) # codimension of X in Y + 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 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] - E, y = gens(RBl)[1:n], gens(RBl)[n+1:end] + E, y = gens(RBl)[1:ngs], gens(RBl)[ngs+1:end] fˣ = hom(RY, RBl, y) - jₓgˣ = x -> sum(E .* fˣ.(pf(x.f))) - - # now we determine the relations in AˣBl + jₓgˣ = x -> sum(E .* fˣ.(sect(x.f))) + + # we set up the relations of ABl - rels = elem_type(RY)[] + Rels = elem_type(RBl)[] # 1) relations from Y - if isdefined(AˣY, :I) - for r in fˣ.(gens(AˣY.I)) push!(rels, r) end + if isdefined(AY, :I) + for r in fˣ.(gens(AY.I)) push!(Rels, r) end end -# 2) relations for AˣX as an AˣY-module - for r in transpose(E) * fˣ.(M) push!(rels, r) 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 fˣ.(PM)*E push!(Rels, r) end -# 3) jₓx ⋅ jₓy = -jₓ(x⋅y⋅ζ) - # recall that E[i] = jₓgˣ(gs[i]) - for j in 1:n-1, k in j:n-1 - push!(rels, E[j] * E[k] + jₓgˣ(X(gs[j] * gs[k])) * (-E[end])) - end + # 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])) -# 4) relation for AˣPN: ∑ gˣcₖ(N) ⋅ ζᵈ⁻ᵏ = 0 - cN = total_chern_class(N)[0:d] # cN[k] = cₖ₋₁(N) - push!(rels, sum([jₓgˣ(cN[k+1]) * (-E[end])^(d-k) for k in 0:d])) + # 4) jₓx ⋅ jₓy = -jₓ(x⋅y⋅ζ) # rule for multiplication, EH, Prop. 13.12 + # recall that E[i] = jₓgˣ(X(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])) + end - # 5) fˣiₓx = jₓ(gˣx ⋅ ctop(Q)) where Q is the tautological quotient bundle on PN - # we have ctop(Q) = ∑ gˣcₖ₋₁(N) ⋅ ζᵈ⁻ᵏ - for j in 1:n + # 5) fˣiₓx = jₓ(gˣx ⋅ ctop(Q)) where Q is the tautological quotient bundle on PN + # we have ctop(Q) = ∑ gˣcₖ₋₁(N) ⋅ ζᵈ⁻ᵏ, EH p. 477 + for j in 1:ngs lhs = fˣ(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])^(d-k) for k in 1:d]) - push!(rels, lhs - rhs) + ### 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]) + push!(Rels, lhs - rhs) end - - AˣBl, _ = quo(RBl , ideal( RBl, rels)) + + Rels = minimal_generating_set(ideal(RBl, Rels)) ### TODO: make this an option? + AˣBl, _ = quo(RBl, Rels) Bl = abstract_variety(Y.dim, AˣBl) -# Bl being constructed, we add the morphisms f, g, and j - RBltoRY = hom(RBl, RY, vcat(repeat([RY()], n), gens(RY))) +# Bl being constructed, we set up the morphisms f, g, and j + + RBltoRY = hom(RBl, RY, vcat(repeat([RY()], ngs), gens(RY))) fₓ = x -> (xf = simplify(x).f; Y(RBltoRY(xf));) fₓ = map_from_func(fₓ, Bl.ring, Y.ring) @@ -293,14 +350,14 @@ function blowup(i::AbstractVarietyMap; symbol::String = "e") g = PN.struct_map ζ = g.O1 - jˣ = vcat([-ζ * g.pullback(X(xi)) for xi in gs], [g.pullback(i.pullback(f)) for f in gens(AˣY)]) + jˣ = vcat([-ζ * g.pullback(X(xi)) for xi in gs], [g.pullback(i.pullback(f)) for f in gens(AY)]) # 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())) jₓ = x -> (xf = simplify(x).f; RX = base_ring(X.ring); ans = RBl(); - for k in d-1:-1:0 + 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 @@ -317,7 +374,7 @@ function blowup(i::AbstractVarietyMap; symbol::String = "e") Bl.T = pullback(f, Y.T) + f.T # chern(Bl.T) can be readily computed from its Chern character, but the following is faster - α = sum(sum((binomial(ZZ(d-j), ZZ(k)) - binomial(ZZ(d-j), ZZ(k+1))) * ζ^k for k in 0:d-j) * g.pullback(chern_class(N, j)) for j in 0:d) + α = 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) @@ -347,12 +404,12 @@ Quotient of multivariate polynomial ring in 2 variables over QQ graded by e -> [1] h -> [1] - by ideal (h^3, e*h, e^3, e^2 + h^2) + by ideal (e*h, e^2 + h^2) ``` """ function blowup_points(X::AbstractVariety, n::Int; symbol::String = "e") - SED = symbol + SED = symbol # SED = "e" if n == 1 symbs = [SED] else @@ -361,7 +418,7 @@ function blowup_points(X::AbstractVariety, n::Int; symbol::String = "e") Bl = X P = abstract_point(base = X.base) for i in 1:n - Bl = blowup(hom(P, Bl, [zero(P.ring)]), symbol=symbs[i])[1] + Bl = blowup(hom(P, Bl, [zero(P.ring) for j = 1:i]), symbol=symbs[i])[1] end set_attribute!(Bl, :description => "Blowup of $X at $n points") Bl.struct_map = hom(Bl, X) diff --git a/experimental/IntersectionTheory/test/runtests.jl b/experimental/IntersectionTheory/test/runtests.jl index 24169adacd13..f14742ffab53 100644 --- a/experimental/IntersectionTheory/test/runtests.jl +++ b/experimental/IntersectionTheory/test/runtests.jl @@ -12,7 +12,7 @@ let pushforward = IntersectionTheory.pushforward # trim!(C.ring) # @test Singular.dimension(C.ring.I) == 0 # @test parent(c) == C.ring - # @test betti(C) == [1, 1] + # @test betti_numbers(C) == [1, 1] # @test basis(C) == [[C.ring(1)], [c]] # @test euler(C) == c # @test euler_characteristic(trivial_line_bundle(C)) == 1//2 * c @@ -105,7 +105,7 @@ let pushforward = IntersectionTheory.pushforward # @test Y1 != Y # @test euler(Y1) == euler(Y) # @test (Y1 → Y).T.ch == 0 - # @test betti(Y1)[3] == 2 + # @test betti_numbers(Y1)[3] == 2 # @test basis(2, Y1) == [h^2, p] # @test intersection_matrix([h^2, p]) == Nemo.matrix(QQ, [3 1; 1 3]) @@ -155,7 +155,7 @@ let pushforward = IntersectionTheory.pushforward G = abstract_grassmannian(2, 4) S, Q = tautological_bundles(G) c1, c2 = gens(G.ring) - @test betti(G) == [1,1,2,1,1] + @test betti_numbers(G) == [1,1,2,1,1] @test euler(G) == 6 @test chern_class(G, 1) == -4chern_class(S, 1) @test integral(total_chern_class(symmetric_power(dual(S), 3))) == 27 @@ -182,7 +182,7 @@ let pushforward = IntersectionTheory.pushforward A, B, C = tautological_bundles(F) @test dim(F) == 3 @test rank.(tautological_bundles(F)) == [1, 1, 1] - @test betti(F) == [1,2,2,1] + @test betti_numbers(F) == [1,2,2,1] @test euler(F) == 6 # flag abstract_variety: TnVariety version @@ -321,7 +321,7 @@ let pushforward = IntersectionTheory.pushforward Bl, E = blowup(structure_map(Z)) @test dim(Bl) == 6 @test euler(Bl) == 18 - @test betti(Bl) == [1,2,4,4,4,2,1] + @test betti_numbers(Bl) == [1,2,4,4,4,2,1] @test [euler_characteristic(exterior_power(cotangent_bundle(Bl), i)) for i in 0:6] == [1,-2,4,-4,4,-2,1] end