Logo University of Nantes

Christoph Sorger

Professor of mathematics at Nantes University

Logo French National Centre for Scientific Research

Chow - A Sage library for computations in intersection theory


Chow is a SAGE package for computations in intersection theory, written together with Manfred Lehn. It is inspired and based on the beautiful Maple library Schubert, of Sheldon Katz and Stein Arild Strømme.

Chow is written in python and makes essential use of Singular via its interface to SAGE. Working with Singular and Sage instead of Maple considerable simplifies the algorithms and in particular allows to compute the Chow ring of a blowup by generators and relations.

We have written then used the package to compute the Euler number of the compact holomorphicially symplectic manifold of dimension eight constructed in Twisted cubics on cubic fourfolds.

The computation is here.

Even though inspired by Schubert, this package was written pretty much from scratch. Whereas we are quite sure that the computation of the above Euler number is correct and that we tested quite carefully the methods of this package it is of course possible if not likely that some bugs remain. If you find one, please contact the authors. In short: use at your own risk!

If you use Macaulay2, use the package Schubert2!

Steiner’s question

A classical example is to compute the number of smooth plane conics tangent to five general conics (this was a question of Steiner in 1848). Each tangency is a degree \(6\) condition on the \(\mathbb{P}^5\) of all conics. To handle double lines, one blows up the Veronese surface in this \(\mathbb{P}^5\), then computes the integral of \((6H-2E)^5 \) where \(E\) is the exceptional divisor. In Chow this is done as follows:

sage: P2 = Proj(2, 'k')
sage: P5 = Proj(5, 'h')
sage: f = P2.hom(['2*k'], P5)
sage: g = Blowup(f)
sage: B = g.codomain()
sage: (e, h) = B.chowring().gens()
sage: ((6*h - 2*e)^5).integral()

Note that \(g\) is the morphism corresponding to the blow up and that the blow up itself it hence its codomain.

\[\begin{array}{ccc} E&\xrightarrow{g}&B\\ \downarrow&&\downarrow\scriptstyle{\sigma}{}\\ \mathbb{P}^2 & \xrightarrow{f} & \mathbb{P}^5 \end{array} \]

By the way, generators and relations as well as the tangent bundle can be retrieved as follows.

sage: B.chowring().gens()
(e, h)
sage: B.chowring().rels()
[h^6, e*h^3, e^3 - 9/2*e^2*h + 15/2*e*h^2 - 4*h^3]
sage: B.tangent_bundle().chern_classes()
[1, -2*e + 6*h, -15/2*e*h + 15*h^2, 9/2*e^2*h - 93/4*e*h^2 + 28*h^3, 27/4*e^2*h^2 + 27*h^4, 12*h^5]
sage: B.betti_numbers()
[1, 2, 3, 3, 2, 1]
sage: B.tangent_bundle().chern_classes()[5].integral()  # The Euler number

Twisted cubics on quintic threefolds

A more challenging example is the computation of the number of twisted cubics on a general quintic threefold.

According to a conjecture of Clemens [C, 1981], the number \(n_d\) of rational curves of degree \(d\) on a general quintic threefold is finite. As far as I understand, this is known thanks to work of S. Katz for \(d\leq 7\) [K], Johnson and Kleiman for \(d\leq 9\) [JK] and Cotteril for \(d=10\) [C1] and \(d=11\) [C2]. Using methods of string theory, Candelas et al [COGP] predicted in 1991 the virtual number of such curves for any \(d\). This has been proven in 1996 by Givental [G] using Gromov-Witten theory (the virtual number and \(n_d\) coincide for all \(d\) where the Clemens conjecture holds).

Here is how these numbers can be computed with /Chow/ for \(d=1, 2, 3\). For \(d=1\) this number is classical; for \(d=2\) it is due to Katz [K] and for \(d=3\) to Ellingsrud and Strømme [ES]. Especially this last computation is challenging, even though straightforward now, thanks to the ability of Chow to compute the full Chow ring of a blowup and its tangent bundle.

Let \(\mathcal{H}_d\) be the component of the Hilbert scheme parameterizing rational degree \(d\) curves in \(\mathbb{P}^4\) (and their degenerations). If \(\mathcal{C}\subset\mathcal{H}_d\times\mathbb{P}^4\) is the universal curve and \(p\) and \(q\) are the projections, then the short exact sequence \(0\to\mathcal{I}_\mathcal{C}\to\mathcal{O}_{\mathcal{H_d}\times\mathbb{P}^4}\to \mathcal{O}_\mathcal{C}\to 0\) twisted by \(q^*(\mathcal{O}_{\mathbb{P}^4}(5))\) induces the short exact sequence

\[0\to p_*\mathcal{I}_\mathcal{C}(5)\to H^0(\mathbb{P}^4,\mathcal{O}_{\mathbb{P}^4}(5))\otimes_{\mathbb{C}} \mathcal{O}_{\mathcal{H}_d}\to p_*\mathcal{O}_\mathcal{C}(5)\to R^1p_*\mathcal{I}_\mathcal{C}(5)\to 0. \]

If \(s\in H^0(\mathbb{P}^4,\mathcal{O}_{\mathbb{P}^4}(5))\), then the induced section in \(p_*\mathcal{O}_\mathcal{C}(5)\) vanishes precisely in those curves [C] of \(\mathcal{H}_d\) contained in the quintic defined by \(s\). Suppose \(d\leq 3\). Then \(R^1p_*\mathcal{I}_\mathcal{C}(5)=0\) and \(p_*\mathcal{O}_\mathcal{C}(5)\) is a vector bundle of rank \(\dim\mathcal{H}\) hence


If \(d=1\) then \(\mathcal{H}_1\) is the Grassmannian of lines in \(\mathbb{P}^4\) and \(p_*\mathcal{O}_\mathcal{C}(5)=S^5Q\) where \(Q\) is the canonical rank \(2\) quotient bundle:

sage: H = Grass(5, 2)  # lines in P4
sage: Q = H.sheaves["universal_quotient"]
sage: Q.symm(5).chern_classes()[H.dimension()].integral()

If \(d=2\), as every conic [\(C\)] \(\in\mathcal{H}_2\) spans a unique plane \(\langle C\rangle\subset\mathbb{P}^4\), there is a map \(f\) to the Grassmannian of 2-planes in \(\mathbb{P}^4\) with fibres the conics in the corresponding \(\mathbb{P}^2\). Hence \(\mathcal{H}_2=\mathbb{P}(S^2Q^*)\) where \(Q\) is the canonical rank \(3\) quotient bundle. Katz showed that \(p_*\mathcal{O}_\mathcal{C}(5)=f^*S^5Q\,\diagup\,(f^*S^3Q\otimes\mathcal{H}_2(-1))\):

sage: G = Grass(5, 3)  # 2-planes in P4
sage: Q = G.sheaves["universal_quotient"]
sage: H = ProjBundle(Q.symm(2).dual())
sage: f = H.base_morphism()  # H -> G
sage: A = f.upperstar(Q.symm(5)) - f.upperstar(Q.symm(3)) * H.o(-1)
sage: A.chern_classes()[H.dimension()].integral()

If \(d=3\), every (generalized) twisted cubic [\(C\)] \(\in\mathcal{H}_3\) spans a hyperplane in \(\mathbb{P}^4\), hence there is a map \(\mathcal{H}_3\to\mathbb{P}^{4\vee}\) with fibres the component \(H_3\) of the Hilbert scheme parameterizing (generalized) twisted cubics in the corresponding \(\mathbb{P}^3\).

The component \(H_3\) had been previously described by Ellingsrud, Piene and Strømme: any curve [\(C\)] \(\in H_3\) determines a net \(H^0(\mathbb{P}^3,\mathcal{I}_C(2)) \subset H^0(\mathbb{P}^3,\mathcal{O}_{\mathbb{P}^3}(2))\) of quadrics. Hence, if \(X\subset Grass(3,H^0(\mathbb{P}^3,\mathcal{O}_{\mathbb{P}^3}(2)))\) denotes the image, we get a map \(\sigma:H_3\to X\). Then \(\sigma\) is identified in [EPS] as the blowup of \(X\) along an incidence variety \(I\subset X\). This construction can be made relative to \(\mathcal{H}_3\to\mathbb{P}^{4\vee}\) and the resulting description is used to compute the above top Chern class.

In Chow we wrote a library, twisted cubics, which defines \(X\), \(I\) and \(f:I\to X\) relative to any base:

sage: P = Grass(1, 5, 'w')
sage: W = P.sheaves["universal_quotient"]
sage: f = map_incidence_to_nets_of_quadrics(W)

In order to obtain \(\mathcal{H}\) it is then sufficient to compute the blowup of \(f\):

sage: g = Blowup(f)
sage: Exc, H = g.domain(), g.codomain()
sage: I, X = Exc.base_chowscheme(), H.base_chowscheme()

Finally it is enough to use the exact sequence (6-1)

\[0\to g_*\mathcal{A}_{Exc}\to\sigma^*\mathcal{A}_X \to p_*\mathcal{O}_\mathcal{C}(5)\to 0 \]

of [ES] and the explicit description of \(\mathcal{A}_{Exc}\) and \(\mathcal{A}_X\) given there to compute as follows:

sage: K1, K2 = I.sheaves["K1"], I.sheaves["K2"]
sage: L1, L2 = I.sheaves["L1"], I.sheaves["L2"]
sage: Q = L1 + K2.dual()
sage: Exc_Q = Exc.base_morphism().upperstar(Q)
sage: Exc_K1 = Exc.base_morphism().upperstar(K1)
sage: AExc = Exc_Q.symm(2) * Exc_K1.determinant() * Exc.o(-1)
sage: AExcH = g.lowerstar(AExc, normal_bundle=Exc.o(-1))

sage: E, F = X.sheaves["E"], X.sheaves["F"]
sage: XW = X.base_morphism().upperstar(W)
sage: AX = (F * XW.symm(2)) - (E * XW.symm(3)) + XW.symm(5)
sage: AXH = H.base_morphism().upperstar(AX)

sage: (AXH - AExcH).chern_classes()[H.dimension()].integral()


Chow is now a branch in the sage source code. Installation may be done as follows:

$ git clone https://github.com/sagemath/sage.git
Cloning into ...
$ cd sage
$ git remote add trac git://trac.sagemath.org/sage.git
$ git trac checkout 27228

[Optional] You will be on the branch t/27228/public/ticket-chow. To go back to the develop branch:

$ git checkout develop
$ git merge t/27228/public/ticket-chow

If git merge above fails for some reasons, please let me know!

Now, we have to compile sage. If your computer is prepared, it is as simple as this:

$ make configure
$ ./configure
$ make -s V=0
$ ./sage

If your computer is not prepared, check the installation prerequisites of the sage documentation.

To test that chow works, run all the tests:

$ ./sage -t src/sage/schemes/chow
[Running tests...]

If you encounter any difficulties, let me know, preferably by e-mail.


The documentation was generated automatically through python’s docstrings, meaning that the html and pdf files are produced at the same time. In particular, the pdf file gets quite long this way (around 100 pages) even if the heart of the documentation is shorter. This documentation is from the initial release but still valid.

As all packages of Sage and Sage itself, /Chow/ is modular and easy to extend with your preferred manifold or method. Send me a patch to integrate it.

Logo Laboratory of Mathematics Jean Leray
UMR n° 6629
Logo Center of Mathematics Henri Lebesgue
Logo Institut Universitaire de France