An introduction to Zeta¶

Tobias Rossmann
University of Galway

No description has been provided for this image
ICTS Bengaluru
December 2024

Zeta (2014–)¶

  • ... is a package for SageMath (which also relies on Singular, Normaliz, LattE, ...)
  • ... provides methods for computing various types (ask, subobject, ...) of zeta functions in "fortunate cases"
  • ... is freely available
  • ... implements techniques outlined here

SageMath (2005–)¶

is a free open-source mathematics software system licensed under the GPL. It builds on top of many existing open-source packages [...]

Mission: Creating a viable free open source alternative to Magma, Maple, Mathematica and Matlab.

  • Freely available
  • Based upon Python
  • Includes GAP, Singular, ...
  • Runs on Linux, Mac OS X, and Windows
  • Command-line ("interactive shell") or browser-based ("notebook") interface

Sage as a symbolic calculator¶

Recall: the ask zeta function of $\mathrm{M}_1(\mathbf Z_p)$ is $\frac{1-p^{-1}T}{(1-T)^2}$.

In [1]:
var('p t') # create symbolic variables
Z = (1-p^(-1)*t)/(1-t)^2
In [2]:
Z.series(t,3) # power series expansion up to given order
Out[2]:
1 + (-1/p + 2)*t + (-2/p + 3)*t^2 + Order(t^3)
In [3]:
Z(p=1) # substitution
Out[3]:
-1/(t - 1)
In [4]:
Z+1 # arithmetic
Out[4]:
-(t/p - 1)/(t - 1)^2 + 1
In [5]:
_.simplify_full()
Out[5]:
(p*t^2 - (2*p + 1)*t + 2*p)/(p*t^2 - 2*p*t + p)
In [6]:
_.factor()
Out[6]:
(p*t^2 - 2*p*t + 2*p - t)/(p*(t - 1)^2)

Remark. Josh Maglione's package BRational can format such rational functions in a nice way.

Installing Zeta¶

  • Linux (x64_64) only at the moment. Mac OS X support will probably come in early(ish) 2025.
  • Steps explained in the manual. TL;DR:
    • download and extract a file
    • start Sage from the same directory

Objectives of this tutorial:¶

  • Illustrate what Zeta can (and cannot do).
  • Describe valid input and the meaning of output.
  • Give examples of theorems found (and sometimes proved) with the help of Zeta.

Getting started¶

In [7]:
import Zeta

Ask zeta functions in Zeta¶

In practice: module representations = matrices of linear forms.

In [8]:
R.<a,b,c,d> = QQ[] # create polynomial ring
A = matrix([[a,b],[c,d]])
A
Out[8]:
[a b]
[c d]

Zeta can attempt to compute "generic local zeta functions".

In [9]:
Z = Zeta.local_zeta_function(A, 'ask')
Z
Out[9]:
(q^2 - t)/(q^2*(t - 1)^2)

Hence, for all but finitely many primes $q$, the ask zeta function of $\mathrm{M}_2(\mathbf Z_q)$ is $\frac{1-q^{-2}T}{(1-T)^2}$. We knew that already.

Note. By default, Zeta attempts to compute ask zeta functions via $\circ$-duals; this can be overwritten.

Experimental mathematics... using Zeta¶

My typical applications of Zeta:

  • Combine Zeta and databases/classification results to look for patterns. Examples:
    • Loop over all nilpotent Lie algebras of small dimension.
    • Loop over all matrices of a given dimension and given shape.
  • "Guess & verify" formulae.
  • Search for counterexamples.

Guess & verify: triangular matrices¶

What is the ask zeta function of

$$\mathfrak{tr}_d(\mathbf Z_p) = \begin{bmatrix} * & \dots & * \\ & \ddots & \vdots \\ & & * \end{bmatrix}?$$

Dimension 2

In [10]:
R.<a,b,c> = QQ[]
A = matrix([[a,b],[0,c]])
A
Out[10]:
[a b]
[0 c]
In [11]:
Zeta.local_zeta_function(A, 'ask')
Out[11]:
-(q - t)^2/(q^2*(t - 1)^3)

Dimension 3

In [12]:
R.<a,b,c,d,e,f> = QQ[]
A = matrix([[a,b,c],[0,d,e],[0,0,f]])
Zeta.local_zeta_function(A, 'ask')
Out[12]:
(q - t)^3/(q^3*(t - 1)^4)

Dimension 4

In [13]:
R = PolynomialRing(QQ, 'x', 10)
x = R.gens()
A = matrix([[x[0],x[1],x[2],x[3]], [0,x[4],x[5],x[6]], [0,0,x[7],x[8]], [0,0,0,x[9]]])
print(A)
%time Zeta.local_zeta_function(A, 'ask')
[x0 x1 x2 x3]
[ 0 x4 x5 x6]
[ 0  0 x7 x8]
[ 0  0  0 x9]
CPU times: user 1.54 s, sys: 56 ms, total: 1.6 s
Wall time: 26.4 s
Out[13]:
-(q - t)^4/(q^4*(t - 1)^5)

Higher dimensions

In [14]:
def generic_upper_triangular_matrix(d):
    R = PolynomialRing(QQ, 'x', binomial(d+1, 2))
    A = matrix(R, d, d)
    it = iter(R.gens())
    for i in range(d):
        for j in range(i, d):
            A[i,j] = next(it)
    return A
In [15]:
A = generic_upper_triangular_matrix(5)
print(A)
[ x0  x1  x2  x3  x4]
[  0  x5  x6  x7  x8]
[  0   0  x9 x10 x11]
[  0   0   0 x12 x13]
[  0   0   0   0 x14]
In [16]:
%time Zeta.local_zeta_function(A, 'ask')
CPU times: user 12.9 s, sys: 90.1 ms, total: 13 s
Wall time: 1min 47s
Out[16]:
(q - t)^5/(q^5*(t - 1)^6)

These computations inspired the following.

Theorem (R. '18). $\mathsf Z_{\mathfrak{tr}_d(\mathbf Z_p)}^{\mathrm{ask}}(T) = \frac{(1-p^{-1}T)^d}{(1-T)^{d+1}}$.

Note that this is a "nice" formula which is not of constant rank type.

Uniformity: $\sqrt{-1}$¶

In [17]:
R.<a,b> = QQ[]
A = matrix([[a,b],[-b,a]])
A
Out[17]:
[ a  b]
[-b  a]
In [ ]:
Zeta.local_zeta_function(A,'ask')
In [19]:
Z = Zeta.local_zeta_function(A,'ask', symbolic=True)
print(Z)
-(q^2*sc_0*t - q^2*t - 2*q*sc_0*t + q^2 + sc_0*t + t^2 - t)/(q^2*(t - 1)^3)
In [20]:
Zeta.common.symbolic_count_varieties[0]
Out[20]:
Subvariety of 1-dimensional torus defined by [x^2 + 1]
In [21]:
Z(sc_0=2).factor() # p == 1 mod 4
Out[21]:
-(q^2*t + q^2 - 4*q*t + t^2 + t)/(q^2*(t - 1)^3)
In [22]:
Z(sc_0=0).factor() # p == 3 mod 4
Out[22]:
(q^2 - t)/(q^2*(t - 1)^2)

Guess & verify? Diagonal matrices¶

What is the ask zeta function of $\mathfrak d_d(\mathbf Z_p) \subset \mathrm M_d(\mathbf Z_p)$?

In [23]:
def generic_diagonal_matrix(d):
    R = PolynomialRing(QQ, 'x', d)
    A = matrix(R,d)
    for i in range(d):
        A[i,i] = R.gen(i)
    return A
In [24]:
Zeta.local_zeta_function(generic_diagonal_matrix(1), 'ask')
Out[24]:
(q - t)/(q*(t - 1)^2)
In [25]:
Zeta.local_zeta_function(generic_diagonal_matrix(2), 'ask')
Out[25]:
-(q^2*t + q^2 - 4*q*t + t^2 + t)/(q^2*(t - 1)^3)
In [26]:
Zeta.local_zeta_function(generic_diagonal_matrix(3), 'ask')
Out[26]:
(q^3*t^2 + 4*q^3*t - 6*q^2*t^2 + q^3 - 12*q^2*t + 12*q*t^2 - t^3 + 6*q*t - 4*t^2 - t)/(q^3*(t - 1)^4)
In [27]:
%time Zeta.local_zeta_function(generic_diagonal_matrix(4), 'ask')
CPU times: user 1.16 s, sys: 96.4 ms, total: 1.26 s
Wall time: 1min 57s
Out[27]:
-(q^4*t^3 + 11*q^4*t^2 - 8*q^3*t^3 + 11*q^4*t - 56*q^3*t^2 + 24*q^2*t^3 + q^4 - 32*q^3*t + 96*q^2*t^2 - 32*q*t^3 + t^4 + 24*q^2*t - 56*q*t^2 + 11*t^3 - 8*q*t + 11*t^2 + t)/(q^4*(t - 1)^5)

Hadamard products¶

  • Exercise: $\mathrm{ask}(\theta \oplus \tilde\theta) = \mathrm{ask}(\theta) \cdotp \mathrm{ask}(\tilde\theta)$.
  • Hadamard product of power series: $(\sum a_n T^n) \star (\sum b_nT^n) = \sum a_nb_n T^n$.
  • Hence: $\mathsf Z_{\theta\oplus\tilde\theta}(T) = \mathsf Z_{\theta}(T) \star \mathsf Z_{\tilde\theta}(T)$

Diagonal matrices (again)¶

  • The ask zeta function of $\mathfrak{d}_d(\mathbf Z_p)$ is the $d$th Hadamard power of $\frac{1-p^{-1}T}{(1-T)^2}$.
  • Surprise! This was computed by Brenti (1994).

Theorem. $\mathsf{Z}_{\mathfrak d_d(\mathbf Z_p)}(T) = \frac{h_d(-p^{-1},T)}{(1-T)^{d+1}}$, where $\mathrm B_d = \{ \pm 1\} \wr \mathrm S_d$ and $$h_d(X,Y) = \sum\limits_{\sigma\in\mathrm B_d} X^{\mathrm N(\sigma)} Y^{\mathrm{d_B}(\sigma)}.$$

Direct sums of more complicated matrix spaces?¶

In [28]:
R.<a,b,c,d,e,f,g,h> = QQ[]
A = matrix([[a],[b]])
B = matrix([[c,d],[e,f],[g,h]])
C = block_diagonal_matrix(A,B)
C
Out[28]:
[a|0 0]
[b|0 0]
[-+---]
[0|c d]
[0|e f]
[0|g h]
In [29]:
Zeta.local_zeta_function(A, 'ask')
Out[29]:
(q - t)/((q*t - 1)*q*(t - 1))
In [30]:
Zeta.local_zeta_function(B, 'ask')
Out[30]:
(q^2 - t)/((q*t - 1)*q^2*(t - 1))
In [31]:
Zeta.local_zeta_function(C, 'ask')
Out[31]:
-(q^4*t - q^3*t + q^3 - 2*q^2*t + q*t^2 - q*t + t)/((q^2*t - 1)*(q*t - 1)*q^3*(t - 1))

Making sense of this formula: see Angela's third lecture 😀

This is "group theory":

  • We already saw: $\mathsf Z^{\mathrm{ask}}_{\mathrm{M}_{d\times(d-1)}(\mathbf{Z}_p)}(T) = \mathsf Z^{\mathrm{ask}}_{\mathfrak{so}_d(\mathbf Z_p)}(T)$.
  • Let $\mathsf F_{2,d}$ be the group scheme naturally arising from the free class-$2$ nilpotent group on $d$ generators. One can show that $\mathsf Z^{\mathrm{cc}}_{\mathsf F_{2,d}\otimes \mathbf Z_p}(T) = \mathsf Z^{\mathrm{ask}}_{\mathfrak{so}_d(\mathbf Z_p)}(p^{\binom d 2}T)$.
  • Up to a simple transformation, our formula above therefore counts conjugacy classes of $\mathsf F_{2,2} \times \mathsf F_{2,3}$!

Class-counting zeta functions¶

  • Zeta can compute local conjugacy class zeta functions attached to nilpotent Lie algebras.
  • Formally: let $\mathfrak g$ be a nilpotent Lie $\mathbf Z$-algebra with $\mathfrak g \approx \mathbf Z^\ell$ additively.
  • (We pretend to) choose an embedding $\mathfrak g \subset \mathfrak n_d(\mathbf Z[\frac 1 N])$.
  • Zeta can attempt to compute the conjugacy class zeta functions of $\exp(\mathfrak g\otimes \mathbf Z_p)$ for $p \gg 0$.
  • $\mathfrak g$ can be defined e.g. by structure constants.

Example: Heisenberg¶

In [32]:
# Basis (x,y,z) with [x,y]=z=(0,0,1), [y,x]=-z=(0,0,-1)
H = Zeta.Algebra([[(0, 0, 0), (0, 0, 1), (0, 0, 0)],
                  [(0, 0,-1), (0, 0, 0), (0, 0, 0)],
                  [(0, 0, 0), (0, 0, 0), (0, 0, 0)]])
In [33]:
Zeta.local_zeta_function(H, 'cc')
Out[33]:
-(t - 1)/((q^2*t - 1)*(q*t - 1))

Other types of zeta functions¶

Zeta can attempt to compute zeta functions enumerating

  • ... subalgebras and ideals of additively finitely generated $\mathbf Z$-algebras,
  • ... (twist isoclasses of) irreducible representations of f.g. nilpotent groups,
  • ... submodules of $\mathbf Z^d$ of finite index which are invariant under a given set of matrices.
In [35]:
Zeta.local_zeta_function(H, 'subalgebras')
Out[35]:
-(q^2*t^2 + q*t + 1)/((q^3*t^2 - 1)*(q*t + 1)*(q*t - 1)*(t - 1))
In [36]:
Zeta.local_zeta_function(H, 'ideals')
Out[36]:
-1/((q^2*t^3 - 1)*(q*t - 1)*(t - 1))
In [34]:
Zeta.local_zeta_function(H, 'reps')
Out[34]:
(t - 1)/(q*t - 1)

The future: there's money in ... AI¶

A group of people in Galway are or will soon be working on combining Zeta (and the methods it uses) and techniques from machine learning.

Feature requests?¶

  • The development of Zeta was primarily driven by my own research needs and things communicated to me.
  • What features or functionality would you find useful?