strataalgebra Documentation

Welcome! The strataalgebra module is designed to compute products in the strata algebra using Sage. The strata algebra is of interest because it has a natural surjective morphism to the tautological ring of the moduli space of curves. The kernel is (conjecturally) described by the Faber-Zagier relations. For more detail, see for example R. Pandharipande’s exposition.

The product structure was implemented by Drew Johnson, based on S. Yang’s note describing the algorithm of Graber and Pandharipande. The program also computes the FZ relations using code copied from A. Pixton’s tautrel.sage program. The code was integrated into this package (with some modifications and optimizations) by Drew Johnson (who takes responsibility for any bugs introduced!).

If you have any questions, comments, or find the code useful, please contact the author: werd2.718@gmail.com.

Installation and loading

Installation should be (hopefully) easy. strataalgebra is distributed as part of the mgn package on PyPI. Click here for installation instructions.

Once it is installed, you can load it in a Sage session by typing:

sage: from strataalgebra import *

How to use

class strataalgebra.StrataAlgebra(base, g, markings=(), make_vars=True)

A ring representing the Strata algebra.

Parameters:
  • base (Ring) – The ring of coefficients you want to work over, usually QQ.
  • g (int) – The genus.
  • markings (tuple) – The markings should be positive integers. Repeats are allowed. Defaults to no markings.
  • make_vars (bool) – Defaults to True. If True, creates variables ps, ps_, ka1, ... , ka{d} (where d is the dimension of the moduli space) that can be used to create basis elements.

First import the module:

sage: from strataalgebra import *

Construct a StrataAlgebra:

sage: SA = StrataAlgebra(QQ,1,(1,2)); SA
Strata algebra with genus 1 and markings (1, 2) over Rational Field

Print the basis elements in a certain codimension, with their (arbitrary) index:

sage: SA.print_strata(2)
**** i: 0
[0 1 2 0 0]
[0 0 0 2 1]
[0 1 1 0 1]

**** i: 1
[0 1 2 0 0]
[0 0 1 1 1]
[0 1 0 1 1]

**** i: 2
[  0   1   2   0]
[ka1   1   1   2]

**** i: 3
[     0      1      2      0]
[     0      1      1 ps + 2]

**** i: 4
[     0      1      2      0]
[     0 ps + 1      1      2]

**** i: 5
[     0      1      2      0]
[     0      1 ps + 1      2]

**** i: 6
[      0       1       2       0]
[      0       1       1       1]
[ka1 + 1       0       0       1]

**** i: 7
[     0      1      2      0]
[     0      1      1      1]
[     1      0      0 ps + 1]

**** i: 8
ka2

**** i: 9
ka1^2

**** i: 10
ka1*ps1

**** i: 11
ka1*ps2

**** i: 12
ps1^2

**** i: 13
ps1*ps2

**** i: 14
ps2^2

Classes that are monomials in \(\psi\) and \(\kappa\) have self-explanatory names.

More complicated classes are displayed in a matrix as follows:

Each row after the first corresponds to a vertex of the graph. The constant term in the entry in the first column is the genus. The kappa classes also appear in the first column. Each column beyond the first corresponds to an edge or a half edge. The entry in the first row gives the label of the half edge, or 0 for a full edge. The constant term of the entry in location (v,e) gives the number of times (0, 1, or 2) that edge e touches vertex v. A ps in entry (v,e) means a \(\psi\)-class associated to the half edge coming out of v. A ps_ may occur when there is a loop at the vertex. The entry in the top left is just padding.

To create classes, you can use their codimension and index. Boundary strata and psi-kappa monomials are represented by their special names, and the rest are represented by s_{codim},{index}

sage: a = SA(2, 1); a
s_2,1
sage: b = SA(2, 7); b
s_2,7
sage: c = SA(2, 11); c
ka1*ps2
sage: d = SA(1,1); d
Dg1

Vector space arithmetic is supported.

sage: 3*b
3*s_2,7
sage: a*72 - b/17
72*s_2,1 - 1/17*s_2,7

Use get_stratum() if you need to know what an unamed basis element means.

sage: SA.get_stratum(2,7)
[     0      1      2      0]
[     0      1      1      1]
[     1      0      0 ps + 1]

You can construct \(\psi,\;\kappa\) monomials and boundary divisors with the methods kappa(), psi(), boundary(), and irr().

You can construct an element using the matrix notation. Just pass a list of lists into your StrataAlgebra.

sage: var('ps') #This is usually done automatically, but we have to do it manually here for the dotests to work.
ps
sage: SA([[0,1,2,0],[1,0,0,ps+1],[0,1,1,1]])
s_2,7

Here is an example of the ps_:

sage: s = StrataAlgebra(QQ,2,())
sage: s.get_stratum(3,9)
[       0        0]
[       1 ps^2 + 2]
sage: s.get_stratum(3,10)
[         0          0]
[         1 ps*ps_ + 2]
sage: var('ps_')
ps_
sage: s([[0,0],[1,ps_*ps+2]])
s_3,10

One of the main features is the computation of the product.

sage: a*b
0

Of course, the codimension was too big. Lets do some less trivial ones.

sage: SA = StrataAlgebra(QQ,1,(1,2,3)); SA
Strata algebra with genus 1 and markings (1, 2, 3) over Rational Field
sage: SA.psi(1) * SA.psi(2)
ps1*ps2
sage: SA.get_stratum(2,7) #just so you can see what it is
[0 1 2 3 0 0]
[0 0 1 1 1 0]
[0 1 0 0 1 1]
[1 0 0 0 0 1]
sage: SA(2,7)*SA.psi(1)
0
sage: SA(2,7)*SA.kappa(1)
s_3,36
sage: SA.get_stratum(3,36)
[      0       1       2       3       0       0]
[      0       0       1       1       1       0]
[      0       1       0       0       1       1]
[ka1 + 1       0       0       0       0       1]
sage: SA.irr()^3
6*s_3,4 - 3*s_3,15 - 3*s_3,23 - 3*s_3,35 + s_3,48 + s_3,49

Everything should work with distributive laws, etc.

sage: SA.kappa(2)*(3*SA.psi(3)-SA(1,3)) == -SA(1,3) *SA.kappa(2) + SA.psi(3)*SA.kappa(2)*3
True

It should work over any ring.

sage: R.<t> = PolynomialRing(ZZ)
sage: SA = StrataAlgebra(R, 2); SA
Strata algebra with genus 2 and markings () over Univariate Polynomial Ring in t over Integer Ring
sage: (3+t)*SA.kappa(1) + t^2 + t*SA.kappa(1)
t^2*one + (2*t+3)*ka1
sage: _^2
t^4*one + (4*t^3+6*t^2)*ka1 + (4*t^2+12*t+9)*ka1^2

There may be problems over a non-divisible ring.

sage: SA.irr()
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for *: 'Rational Field' and 'Strata algebra with genus 2 and markings () over Univariate Polynomial Ring in t over Integer Ring'

Also, repeated names of the markings are allowed. The following corresponds to \(\overline{\mathcal M}_{1,2}/S_2\). Compare the codimension 2 strata to our earlier example.

sage: SA = StrataAlgebra(QQ,1,(1,1)); SA
Strata algebra with genus 1 and markings (1, 1) over Rational Field
sage: SA.print_strata(2)
**** i: 0
[0 1 1 0 0]
[0 0 0 2 1]
[0 1 1 0 1]

**** i: 1
[0 1 1 0 0]
[0 0 1 1 1]
[0 1 0 1 1]

**** i: 2
[  0   1   1   0]
[ka1   1   1   2]

**** i: 3
[     0      1      1      0]
[     0      1      1 ps + 2]

**** i: 4
[     0      1      1      0]
[     0 ps + 1      1      2]

**** i: 5
[      0       1       1       0]
[      0       1       1       1]
[ka1 + 1       0       0       1]

**** i: 6
[     0      1      1      0]
[     0      1      1      1]
[     1      0      0 ps + 1]

**** i: 7
ka2

**** i: 8
ka1^2

**** i: 9
ka1*ps1

**** i: 10
ps1^2

**** i: 11
ps1*ps1
FZ_betti(codim=None)

Give the dimension of the cohomology of moduli space of curves, as predicted by the Faber-Zagier relations. If the codimension is omited, return a list of all of them.

Parameters:codim – Optional. The codimension you want.
sage: from strataalgebra import *
sage: StrataAlgebra(QQ, 2, (1,)).FZ_betti()
[1, 3, 5, 3, 1]
sage: StrataAlgebra(QQ, 2, (1,)).FZ_betti(2)
5

See also

hilbert()

FZ_matrix(r)

Return the matrix of Faber-Zagier relations.

Parameters:r – The codimension.
Return type:Matrix

The columns correspond to the basis elements of the Strata algebra, and each row is a relation.

Notice that this matrix considers the kappa classes to be in the monomial basis. Thus, is different than the output of Pixton’s original taurel.sage program.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,0,(1,2,3,4))
sage: s.FZ_matrix(1)
[  -9/4   -9/4   -9/4 -153/4   45/4   45/4   45/4   45/4]
[   3/2    3/2    3/2  -33/2  -21/2   15/2   15/2   15/2]
[   3/2    3/2    3/2  -33/2   15/2  -21/2   15/2   15/2]
[   3/2    3/2    3/2  -33/2   15/2   15/2  -21/2   15/2]
[   3/2    3/2    3/2  -33/2   15/2   15/2   15/2  -21/2]
[ -15/4   21/4   21/4  -15/4  -21/4  -21/4   15/4   15/4]
[  21/4  -15/4   21/4  -15/4  -21/4   15/4  -21/4   15/4]
[  21/4   21/4  -15/4  -15/4  -21/4   15/4   15/4  -21/4]
[  21/4   21/4  -15/4  -15/4   15/4  -21/4  -21/4   15/4]
[  21/4  -15/4   21/4  -15/4   15/4  -21/4   15/4  -21/4]
[ -15/4   21/4   21/4  -15/4   15/4   15/4  -21/4  -21/4]
[ -15/4  -15/4  -15/4  -15/4   15/4   15/4   15/4   15/4]
FZ_matrix_pushforward_basis(r)

Return the matrix of Faber-Zagier relations, using the “pushforward” basis, NOT the kappa monomial basis that the rest of the code uses.

Parameters:r – The codimension.
Return type:Matrix

The columns correspond to the basis elements of the Strata algebra, and each row is a relation. This matrix should be the same as Pixton’s original tautrel.sage program after permuting columns.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,0,(1,2,3,4))
sage: s.FZ_matrix_pushforward_basis(1)
[  -9/4   -9/4   -9/4 -153/4   45/4   45/4   45/4   45/4]
[   3/2    3/2    3/2  -33/2  -21/2   15/2   15/2   15/2]
[   3/2    3/2    3/2  -33/2   15/2  -21/2   15/2   15/2]
[   3/2    3/2    3/2  -33/2   15/2   15/2  -21/2   15/2]
[   3/2    3/2    3/2  -33/2   15/2   15/2   15/2  -21/2]
[ -15/4   21/4   21/4  -15/4  -21/4  -21/4   15/4   15/4]
[  21/4  -15/4   21/4  -15/4  -21/4   15/4  -21/4   15/4]
[  21/4   21/4  -15/4  -15/4  -21/4   15/4   15/4  -21/4]
[  21/4   21/4  -15/4  -15/4   15/4  -21/4  -21/4   15/4]
[  21/4  -15/4   21/4  -15/4   15/4  -21/4   15/4  -21/4]
[ -15/4   21/4   21/4  -15/4   15/4   15/4  -21/4  -21/4]
[ -15/4  -15/4  -15/4  -15/4   15/4   15/4   15/4   15/4]

See also

FZ_matrix()

MgnLb_class(index)

Returns the class corresponding to the index from Carl Faber’s MgnLb Maple program. This is useful for testing purposes.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,1,(1,2))
sage: s.MgnLb_class(1)
ps1
sage: s.MgnLb_class(4)
ka2
sage: s.MgnLb_class(6)
1/2*D_irr
sage: s.MgnLb_class(2)
ps2
MgnLb_int(index_list)

Computes an integral of boundary divisors, kappa classes, and psi classes.

Parameters:index_list – A list of indices of classes, according the the scheme of Carl Faber’s MgnLb Maple program. This function is useful because so you can test our implementation of the product and the FZ_relations.
Return type:Rational

Examples:

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,1,(1,2))
sage: s.MgnLb_int([1,6])
1/2
sage: s.MgnLb_int([1,2])
1/24
sage: s.MgnLb_int([4])
1/24

See also

MgnLb_class()

basis_integrals

File: /Users/drewjohnson/mgn/strataalgebra/strataalgebra.py (starting at line 491)

Return a list of numbers corresponding to the integrals of the basis elements in the top codimension.

This is computed via the FZ relations, so it is probably not fast. However, it is a nice check.

The value is cached, so you only have to compute it once per session.

This is used by integrate() which is the more likely way you will want to use it.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,1,(1,))
sage: s.print_strata(1)
**** i: 0
D_irr

**** i: 1
ka1

**** i: 2
ps1

sage: s.basis_integrals()
[1, 1/24, 1/24]
boundary(g1, markings1=())

Return a boundary divisor with genus g1 and markings1 points on one component

Parameters:
  • g1 (int) – The genus on one component
  • markings1 (list) – A list or tuple of markings on the one component. Defaults to the empty list.
Return type:

StrataAlgebraElement

Note that if the two components are the same, it will return the stratum with a coefficient of 1/2.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ, 1, (1,2,3))
sage: s.boundary(0, (1,2))
Dg0m1_2
sage: s.boundary(1,[3])
Dg0m1_2
sage: s = StrataAlgebra(QQ, 2)
sage: s.boundary(1)
1/2*Dg1

Each component must still be stable.

sage: s.boundary(2)
Traceback (most recent call last):
...
KeyError: Dg0
do_all_products()

Compute all the products of basis elements of the ring (thus caching their values). This could take a long time for some rings.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,1,(1,))
sage: s.do_all_products()
get_stratum(r, j)

Get the StrataGraph associated a a codimension and an index.

Parameters:
  • r – The codimension
  • j – The index
Return type:

StrataGraph

See StrataAlgebra documentation for examples.

hilbert(codim=None)

Give the number of basis elements in the Strata algebra for the given codimension (the Hilbert function). If the codimension is omitted, return a list of all of them.

This is NOT the Betti numbers for the moduli space of curves! For that see FZ_betti().

Parameters:codim (int) – Optional. The codimension you want.
sage: from strataalgebra import *
sage: StrataAlgebra(QQ, 2, (1,)).hilbert()
[1, 4, 17, 49, 92]
sage: StrataAlgebra(QQ, 2, (1,)).hilbert(2)
17
irr()

Make the irreducible boundary. It will be returned with a coefficient of 1/2.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ, 1, (1,2))
sage: s.irr()
1/2*D_irr
kappa(a)

Return a kappa class.

Parameters:a (int) – The subscript (codimension) of the kappa class you want.
Return type:StrataAlgebraElement
sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,2,())
sage: s.kappa(1)
ka1
sage: s.kappa(3)
ka3
sage: s.kappa(1)*s.kappa(2)
ka1*ka2
sage: s.kappa(2)*s.kappa(2)
0
sage: s.boundary(1,())*s.kappa(1)
s_2,4
sage: s.get_stratum(2,4)
[      0       0]
[ka1 + 1       1]
[      1       1]

The subscript must be less than or equal to the dimension of the moduli space.

sage: s.kappa(4)
Traceback (most recent call last):
...
KeyError: 4
print_strata(r)

Print all the strata, with their indexes, in codimension r.

Parameters:r – The codimension
Returns:None

See StrataAlgebra documentation for examples.

psi(mark)

Return a psi class.

Parameters:mark (int) – The mark that the \(\psi\)-class is associated to.
Return type:StrataAlgebraElement

Examples

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,0,(1,2,3,4,5))
sage: psi1 = s.psi(1); psi1
ps1
sage: psi2 = s.psi(2); psi2
ps2
sage: psi1*psi2
ps1*ps2
sage: (psi1*psi2).integrate()
2

Note that the psi variables are not automatically injected into the namespace

sage: ps1
Traceback (most recent call last):
...
NameError: name 'ps1' is not defined

In case of repeated marks, notice that the \(\psi\)-class is the pushforward under the quotient map. Observe:

sage: s = StrataAlgebra(QQ,1,(1,1))
sage: s.psi(1)^2
ps1^2 + ps1*ps1
sage: s.psi(2)
Traceback (most recent call last):
...
ValueError: tuple.index(x): x not in tuple
sage: s = StrataAlgebra(QQ,1,(1,1,1))
sage: s.psi(1)^2
2*ps1^2 + 4*ps1*ps1
sage: s.psi(1)^3
4*ps1^3 + 24*ps1^2*ps1 + 8*ps1*ps1*ps1
sage: var('ps') #This should be done automatically.
ps
sage: s([[0,1,1,1],[1,ps^3+1,1,1]])
ps1^3
sage: s = StrataAlgebra(QQ,0,(1,1,1,2,2))
sage: s.psi(1)*s.psi(2)
12*ps1*ps2
sage: s.psi(1)*s.psi(1)
4*ps1^2 + 8*ps1*ps1

This maybe looks surprising, but it makes sense with the formula

\[\pi_*(\alpha) \pi_*(\beta) = \frac{1}{|G|} \pi_* \left( \sum_{\sigma, \tau \in G} \sigma_*(\alpha) \tau_*(\beta) \right)\]

for two class \(\alpha,\;\beta \in H^*(X)\) where \(\pi: X \rightarrow X/G\) is the quotient map and \(G\) is a finite group.

StrataAlgebraElement.integrate()

Return the integral of this class, i.e. its degree in the top codimension.

Classes of codimension less that the dimension of the moduli space will integrate to 0.

This uses the FZ relations to perform the integration. It is probably not very efficient. But it provides a nice check of the implementation. Consider using the topintersections module if you need to compute something quickly.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,1,(1,2))
sage: (s.psi(1)*s.psi(2)).integrate()
1/24
sage: s.kappa(2).integrate()
1/24
sage: s.get_stratum(2,0) #just so you can see it.
[0 1 2 0 0]
[0 0 0 2 1]
[0 1 1 0 1]
sage: s(2,0).integrate()
1
sage: s(1,2).integrate()
0
sage: (42*s(2,0) + s(1,1) + 48*s.kappa(2)).integrate()
44    
StrataAlgebraElement.dict()

Return a dictionary with keys as StrataGraph objects and values as the coefficient of that stratum in this element.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,1,(1,2,3)); s
Strata algebra with genus 1 and markings (1, 2, 3) over Rational Field
sage: a = s.psi(1)*s.psi(2) - 7* s.kappa(3); a
ps1*ps2 - 7*ka3
sage: a.dict()
{ps1*ps2: 1, ka3: -7}
StrataAlgebraElement.codim()

Returns the codimensions of this StrataAlgebraElement.

If it is not homogeneous, it retunrs the maximum codimension of a basis element with a non-zero coefficient.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,2)
sage: s(1,0).codim()
1
sage: s(2,1).codim()
2
sage: s(0,0).codim()
0
sage: (35*s(2,3) - 7*s(1,1) + s.kappa(2) - s(0,0)).codim()
2
sage: s.zero().codim()
-1
StrataAlgebraElement.in_kernel()

Determine whether this StrataAlgebraElement is in the span of the FZ relations, and hence in the kernel of the map to the tautological ring.

sage: from strataalgebra import *
sage: s = StrataAlgebra(QQ,0,(1,2,3,4,5))
sage: b = s.boundary(0,(1,2,5)) + s.boundary(0,(1,2)) - s.boundary(0,(1,3,5)) - s.boundary(0,(1,3))
sage: b
Dg0m1_2_5 + Dg0m1_2 - Dg0m1_3_5 - Dg0m1_3
sage: b.in_kernel()
True
sage: (s.psi(1) - s.psi(2)).in_kernel()
False

It should work fine for non-homogeneous things as well.

sage: (b + s.psi(1)).in_kernel()
False
sage: (b + s.psi(1)**2 - s.psi(2)**2).in_kernel()
True

Testing

The tests module tests the implementation of the product and the FZ relations by comparing them to the topintersections code.

You can change which pairs you want to check by modifying the g_n_pairs_to_check variable in the source code tests.py.

sage: import strataalgebra.tests as tests
sage: tests.run() # not tested

The comment is there so that the doctests don’t try to run it.

You can also test the examples from this file using Sage’s doctest.

Indices and tables