Abelian functions¶
Riemann theta functions generalize the Jacobi theta functions from one complex variable to several. They arose in Riemann’s nineteenth-century theory of Abelian functions and compact Riemann surfaces. Today they are fundamental tools in complex analysis and algebraic geometry, and occur in finite-gap and quasiperiodic solutions of integrable systems.
In genus \(g\), the argument \(\mathbf{z}\in\mathbb C^g\) is a column vector and the period matrix \(\boldsymbol{\tau}\in\mathbb C^{g\times g}\) is symmetric with positive-definite imaginary part.
Theta functions are quasiperiodic. For integer vectors \(\mathbf{m},\mathbf{n}\in\mathbb Z^g\), the zero-characteristic function satisfies
Although theta functions are quasiperiodic, suitable ratios and combinations of them give multiply-periodic Abelian functions. In genus two, such Abelian functions are meromorphic functions of two complex variables with a period lattice of rank four, generated in normalized coordinates by the columns of \(\mathbf{I}_2\) and \(\boldsymbol{\tau}\).
Riemann theta functions¶
- mpmath.rtheta(z, tau, characteristic=None, derivative=0)¶
Evaluates the Riemann theta function. In genus \(g\), the argument \(\mathbf{z}\in\mathbb C^g\) is a column vector and the period matrix \(\boldsymbol{\tau}\in\mathbb C^{g\times g}\) is symmetric with positive-definite imaginary part. The convention is
\[\theta(\mathbf{z}\mid\boldsymbol{\tau}) = \sum_{\mathbf{n}\in\mathbb Z^g} \exp\!\left(\pi i\,\mathbf{n}^{T}\boldsymbol{\tau}\,\mathbf{n} + 2\pi i\,\mathbf{n}^{T}\mathbf{z}\right).\]The argument \(\mathbf{z}\) must be a length-\(g\) sequence. The period matrix \(\boldsymbol{\tau}\) must be a square matrix with \(g\) rows and columns. Entries opposite the diagonal that differ only by the current
almosteqtolerance are averaged; materially asymmetric matrices raiseValueError.Characteristics
Passing
characteristic=(a, b)evaluates\[\begin{split}\theta\!\begin{bmatrix}\mathbf{a}\\\mathbf{b}\end{bmatrix} (\mathbf{z}\mid\boldsymbol{\tau}) = \sum_{\mathbf{n}\in\mathbb Z^g} \exp\!\left( \pi i\,(\mathbf{n}+\mathbf{a})^{T}\boldsymbol{\tau}\, (\mathbf{n}+\mathbf{a}) + 2\pi i\,(\mathbf{n}+\mathbf{a})^{T} (\mathbf{z}+\mathbf{b})\right).\end{split}\]Here \(\mathbf{a},\mathbf{b}\in\mathbb R^g\) are literal real vectors, rather than packed characteristic bits. Arbitrary real characteristics are accepted; half-integer characteristics are the most common.
Derivatives
derivative=(d0, ..., d(g-1))requests the multi-index derivative\[\frac{\partial^{d_0+\cdots+d_{g-1}}\theta} {\partial z_0^{d_0}\cdots\partial z_{g-1}^{d_{g-1}}}.\]The entries must be nonnegative integers. In genus one, an integer derivative order can be supplied directly for consistency with
jtheta. Derivatives are with respect to the components of \(\mathbf{z}\), not the angular argument used byjtheta.Examples
Evaluate a genus-two theta value:
>>> from mpmath import mp, rtheta >>> mp.pretty = True >>> tau = [[1.0j, 0.05j], [0.05j, 1.2j]] >>> rtheta([0.1, 0.2], tau) (1.08592896533944 + 0.0j)
A half-characteristic and a mixed derivative use literal vectors and a derivative multi-index:
>>> characteristic = ([0.5, 0], [0, 0.5]) >>> rtheta([0.1, 0.2], tau, characteristic, derivative=(1, 1)) (-0.289794493099238 + 0.0j)
In genus one, set \(q=\exp(\pi i\tau)\) and write \(z=w/\pi\). The four standard Jacobi theta functions then correspond to
\[\begin{split}\begin{aligned} \theta\!\begin{bmatrix}1/2\\1/2\end{bmatrix} (w/\pi\mid\tau) &= -\vartheta_1(w,q), & \theta\!\begin{bmatrix}1/2\\0\end{bmatrix} (w/\pi\mid\tau) &= \vartheta_2(w,q), \\ \theta\!\begin{bmatrix}0\\0\end{bmatrix} (w/\pi\mid\tau) &= \vartheta_3(w,q), & \theta\!\begin{bmatrix}0\\1/2\end{bmatrix} (w/\pi\mid\tau) &= \vartheta_4(w,q). \end{aligned}\end{split}\]For example, the zero-characteristic identity can be checked directly:
>>> from mpmath import almosteq, expjpi, jtheta, pi >>> tau1 = 0.2+0.9j >>> w = 0.3+0.1j >>> almosteq(rtheta([w/pi], [[tau1]]), ... jtheta(3, w, expjpi(tau1))) True
Plots
The following plots show two real slices and the modulus over two real variables for genus-two period matrices. Similar slices and surfaces are illustrated in DLMF section 21.4.
import matplotlib.pyplot as plt from mpmath import j, plot, re, rtheta tau = [[j, -0.5], [-0.5, j]] curves = [ lambda x: re(rtheta([x, x/2], tau)), lambda x: re(rtheta([x, 2*x], tau)), ] fig, ax = plt.subplots() plot(curves, [-2, 2], axes=ax) ax.legend([r"$z=(x,x/2)$", r"$z=(x,2x)$"]) fig.savefig("rtheta.png")
import matplotlib.pyplot as plt from mpmath import j, rtheta, splot tau = [[j, 0.5], [0.5, j]] fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) surface = lambda x, y: abs(rtheta([x, y], tau)) splot(surface, [-1, 1], [-1, 1], points=35, keep_aspect=False, axes=ax, plot3d_kwargs={"cmap": "viridis"}) ax.set_zlabel(r"$|\theta(z\mid\tau)|$") fig.savefig("rtheta_surface.png")
Accuracy
The truncation controls absolute error in the scaled series. Near a zero of theta, cancellation can prevent full relative accuracy.
Performance
This implementation is intended primarily for low-genus applications. Computation time depends strongly on \(\boldsymbol{\tau}\) and can increase rapidly with the genus and requested precision. Automatic reduction can make many otherwise slow inputs practical, but general high-genus evaluation may remain expensive.
References
[DLMF] Chapter 21, Multidimensional Theta Functions.
B. Deconinck, M. Heil, A. Bobenko, M. van Hoeij and M. Schmies, Computing Riemann Theta Functions, Mathematics of Computation 73 (2004), 1417-1442.
Wolfram Language, SiegelTheta.
- mpmath.rtheta_jet(z, tau, order, characteristic=None)¶
Evaluates a derivative jet of the Riemann theta function. A jet is the function value together with all partial derivatives through the requested total order at the same point.
For example, in genus two the order-two jet aligns the multi-indices and derivatives as follows (all evaluated at the same \(\mathbf{z}\)):
\[\begin{split}\begin{gathered} \big((0,0),(1,0),(0,1),(2,0),(1,1),(0,2)\big) \\ \left(\theta, \frac{\partial\theta}{\partial z_0}, \frac{\partial\theta}{\partial z_1}, \frac{\partial^2\theta}{\partial z_0^2}, \frac{\partial^2\theta}{\partial z_0\partial z_1}, \frac{\partial^2\theta}{\partial z_1^2}\right) \end{gathered}.\end{split}\]ordermust be a nonnegative integer. The result is a dictionary mapping each derivative multi-index to its value. Its keys are inserted in graded reverse lexicographic order: total order first, then the earlier coordinates first within each order.Values are ordinary derivatives, using the same convention as the
derivativeargument tortheta(); they are not divided by multi-index factorials. All components are accumulated in one lattice traversal, which is normally much faster than separate calls tortheta().Examples
Evaluate a value, gradient and Hessian components together:
>>> from mpmath import almosteq, rtheta, rtheta_jet >>> tau = [[1.0j, 0.05j], [0.05j, 1.2j]] >>> z = [0.1, 0.2] >>> jet = rtheta_jet(z, tau, 2) >>> list(jet) [(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2)] >>> almosteq(jet[(1, 1)], rtheta(z, tau, derivative=(1, 1))) True
Characteristics use the same literal
(a, b)convention asrtheta().