From f3dd05a261dc2d616a1efab20081135eac5b415d Mon Sep 17 00:00:00 2001 From: Sam Schiavone Date: Fri, 17 Apr 2026 11:55:10 -0400 Subject: [PATCH 1/4] working on getting acb_theta_jet in Magma; need to rebuild using meson --- src/flint/types/acb_mat.pyi | 4 ++ src/flint/types/acb_mat.pyx | 19 +++++++ src/flint/types/acb_theta.pyi | 2 + src/flint/types/acb_theta.pyx | 101 ++++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) diff --git a/src/flint/types/acb_mat.pyi b/src/flint/types/acb_mat.pyi index 87a8736b..c497cae1 100644 --- a/src/flint/types/acb_mat.pyi +++ b/src/flint/types/acb_mat.pyi @@ -97,6 +97,10 @@ class acb_mat(flint_mat[acb]): def theta(self, z: acb_mat, square: bool = False) -> acb_mat: ... + def theta_jet(self, z: acb_mat, ord: int, square: bool = False) -> list[acb_mat]: ... + +acb_theta_jet(zvec, nb_in, tau, ord, ab, all, square=square) + def str(self, n: int = 0, radius: bool = True, more: bool = False, condense: int = 0) -> _str: ... def repr(self) -> _str: ... def __str__(self) -> _str: ... diff --git a/src/flint/types/acb_mat.pyx b/src/flint/types/acb_mat.pyx index ae65fe71..7969fd34 100644 --- a/src/flint/types/acb_mat.pyx +++ b/src/flint/types/acb_mat.pyx @@ -839,3 +839,22 @@ cdef class acb_mat(flint_mat): except ImportError: raise NotImplementedError("acb_mat.theta needs Flint >= 3.1.0") return acb_theta(z, tau, square=square) + + def theta_jet(zvec, nb_in, tau, ord, square=False): + r""" + Computes Taylor approximation for the vector-valued Riemann theta function + `(\theta_{a,b}(z, \tau) : a, b \in \{0,1\}^{g})` or its squares, + where `\tau` is given by ``self``. + + This is a wrapper for :func:`.acb_theta_jet.acb_theta_jet`; see the + documentation for that method for details and examples. + This follows the same conventions of the C-function + `acb_theta_jet `_ + for the ordering of the theta characteristics. + + """ + try: + from .acb_theta import acb_theta_jet + except ImportError: + raise NotImplementedError("acb_mat.theta needs Flint >= 3.1.0") + return acb_theta_jet(zvec, nb_in, tau, ord, square=square) diff --git a/src/flint/types/acb_theta.pyi b/src/flint/types/acb_theta.pyi index 37f1e1e3..37b69b74 100644 --- a/src/flint/types/acb_theta.pyi +++ b/src/flint/types/acb_theta.pyi @@ -4,3 +4,5 @@ from flint.types.acb_mat import acb_mat def acb_theta(z: acb_mat, tau: acb_mat, square: bool | int = False) -> acb_mat: ... + +def acb_theta_jet(z: acb_mat, ord: int, square: bool = False) -> list[acb_mat]: ... diff --git a/src/flint/types/acb_theta.pyx b/src/flint/types/acb_theta.pyx index 80ed5df1..a50c211f 100644 --- a/src/flint/types/acb_theta.pyx +++ b/src/flint/types/acb_theta.pyx @@ -95,3 +95,104 @@ def acb_theta(acb_mat z, acb_mat tau, ulong square=False): res.append(r) _acb_vec_clear(theta, nb) return acb_mat([res]) + +#def acb_theta_jet(acb_mat z, acb_mat tau, slong ord, ulong square=False): + # r""" + # Computes derivatives of the vector valued Riemann theta function + # `(\theta_{a,b}(z, \tau) : a, b \in \{0,1\}^{g})` or its squares. + # + # This is a wrapper for the C-function + # `acb_theta_jet `_ + # and it follows the same conventions for the ordering of the theta characteristics. + # + # This should be used via the method :meth:`.acb_mat.theta`, explicitly ``tau.theta(z)``. + # """ + # g = tau.nrows() + # assert tau.ncols() == g + # assert z.nrows() == g + # assert z.ncols() == 1 + # + # # convert input + # cdef acb_ptr zvec + # zvec = _acb_vec_init(g) + # cdef long i + # for i in range(g): + # acb_set(zvec + i, acb_mat_entry(z.val, i, 0)) + # cdef slong nb_in = 1 + # cdef ulong ab = 0 + # cdef ulong all = True + # + # # initialize the output + # cdef slong nb = 1 << (2 * g) + # # 1. Calculate the length of the jet for one characteristic + # # This is the number of multi-indices (alpha) such that |alpha| < ord + # cdef slong nj = acb_theta_jet_len(g, ord) + # cdef acb_ptr theta = _acb_vec_init(nb) + # + # acb_theta_jet(theta, zvec, nb_in, tau.val, ord, ab, all, square, getprec()) + # _acb_vec_clear(zvec, g) + # # copy the output + # res = [] + # cdef acb r + # for i in range(nb): + # r = acb.__new__(acb) + # acb_set(r.val, theta + i) + # res.append(r) + # _acb_vec_clear(theta, nb) + # return acb_mat([res]) + +def acb_theta_jet(acb_mat z, acb_mat tau, slong ord, ulong square=False): + r""" + Corrected wrapper for acb_theta_jet to handle multivariate Taylor expansions. + """ + cdef slong g = tau.nrows() + if g == 0: + return [] + + # 1. Calculate the length of the jet for one characteristic + # This is the number of multi-indices (alpha) such that |alpha| < ord + cdef slong nj = acb_theta_jet_len(g, ord) + + # 2. Total number of characteristics + cdef slong nb = 1 << (2 * g) + + # 3. Total number of acb elements to allocate + # FLINT stores nj coefficients for each of the nb characteristics + cdef slong total_size = nb * nj + + # Convert input z to acb_ptr + cdef acb_ptr zvec = _acb_vec_init(g) + cdef slong i, j + for i in range(g): + acb_set(zvec + i, acb_mat_entry(z.val, i, 0)) + + # Parameters for characteristics + cdef slong nb_in = 1 # Number of input z vectors + cdef ulong ab = 0 # Base characteristic + cdef ulong all = True # Compute all 2^2g characteristics + + # Initialize the output buffer + cdef acb_ptr theta = _acb_vec_init(total_size) + + # Call the FLINT C function + # Note: Computes all partial derivatives up to total order 'ord' + acb_theta_jet(theta, zvec, nb_in, tau.val, ord, ab, all, square, getprec()) + + # 4. Copy the output into a structured format + # We return a list of lists: res[char_idx] = [coeff_0, coeff_1, ...] + res = [] + cdef acb r + for i in range(nb): + char_jet = [] + for j in range(nj): + r = acb.__new__(acb) + # Offset: characteristic index * length of one jet + coefficient index + acb_set(r.val, theta + (i * nj + j)) + char_jet.append(r) + res.append(char_jet) + + # Cleanup + _acb_vec_clear(zvec, g) + _acb_vec_clear(theta, total_size) + + return res From 75b6aabcaa4f94b431de240859b7a00fcd14affb Mon Sep 17 00:00:00 2001 From: JHanselman Date: Fri, 24 Apr 2026 15:43:15 +0200 Subject: [PATCH 2/4] Some bug-fixing --- src/flint/types/acb_mat.pyi | 3 +- src/flint/types/acb_mat.pyx | 8 +-- src/flint/types/acb_theta.pyi | 2 +- src/flint/types/acb_theta.pyx | 96 ++++++++++++++++++----------------- 4 files changed, 55 insertions(+), 54 deletions(-) diff --git a/src/flint/types/acb_mat.pyi b/src/flint/types/acb_mat.pyi index c497cae1..755071a4 100644 --- a/src/flint/types/acb_mat.pyi +++ b/src/flint/types/acb_mat.pyi @@ -97,9 +97,8 @@ class acb_mat(flint_mat[acb]): def theta(self, z: acb_mat, square: bool = False) -> acb_mat: ... - def theta_jet(self, z: acb_mat, ord: int, square: bool = False) -> list[acb_mat]: ... + def theta_jets(self, z: acb_mat, ord: int, square: bool = False) -> list[acb_mat]: ... -acb_theta_jet(zvec, nb_in, tau, ord, ab, all, square=square) def str(self, n: int = 0, radius: bool = True, more: bool = False, condense: int = 0) -> _str: ... def repr(self) -> _str: ... diff --git a/src/flint/types/acb_mat.pyx b/src/flint/types/acb_mat.pyx index 7969fd34..8397a589 100644 --- a/src/flint/types/acb_mat.pyx +++ b/src/flint/types/acb_mat.pyx @@ -838,9 +838,9 @@ cdef class acb_mat(flint_mat): from .acb_theta import acb_theta except ImportError: raise NotImplementedError("acb_mat.theta needs Flint >= 3.1.0") - return acb_theta(z, tau, square=square) + return acb_theta(z, 2*tau, square=square) - def theta_jet(zvec, nb_in, tau, ord, square=False): + def theta_jets(tau, z, ord, square=False): r""" Computes Taylor approximation for the vector-valued Riemann theta function `(\theta_{a,b}(z, \tau) : a, b \in \{0,1\}^{g})` or its squares, @@ -854,7 +854,7 @@ cdef class acb_mat(flint_mat): """ try: - from .acb_theta import acb_theta_jet + from .acb_theta import acb_theta_jets except ImportError: raise NotImplementedError("acb_mat.theta needs Flint >= 3.1.0") - return acb_theta_jet(zvec, nb_in, tau, ord, square=square) + return acb_theta_jets(z, tau, ord, square=square) diff --git a/src/flint/types/acb_theta.pyi b/src/flint/types/acb_theta.pyi index 37b69b74..5d06b495 100644 --- a/src/flint/types/acb_theta.pyi +++ b/src/flint/types/acb_theta.pyi @@ -5,4 +5,4 @@ from flint.types.acb_mat import acb_mat def acb_theta(z: acb_mat, tau: acb_mat, square: bool | int = False) -> acb_mat: ... -def acb_theta_jet(z: acb_mat, ord: int, square: bool = False) -> list[acb_mat]: ... +def acb_theta_jets(z: acb_mat, ord: int, square: bool = False) -> list[acb_mat]: ... diff --git a/src/flint/types/acb_theta.pyx b/src/flint/types/acb_theta.pyx index a50c211f..f615af89 100644 --- a/src/flint/types/acb_theta.pyx +++ b/src/flint/types/acb_theta.pyx @@ -96,62 +96,18 @@ def acb_theta(acb_mat z, acb_mat tau, ulong square=False): _acb_vec_clear(theta, nb) return acb_mat([res]) -#def acb_theta_jet(acb_mat z, acb_mat tau, slong ord, ulong square=False): - # r""" - # Computes derivatives of the vector valued Riemann theta function - # `(\theta_{a,b}(z, \tau) : a, b \in \{0,1\}^{g})` or its squares. - # - # This is a wrapper for the C-function - # `acb_theta_jet `_ - # and it follows the same conventions for the ordering of the theta characteristics. - # - # This should be used via the method :meth:`.acb_mat.theta`, explicitly ``tau.theta(z)``. - # """ - # g = tau.nrows() - # assert tau.ncols() == g - # assert z.nrows() == g - # assert z.ncols() == 1 - # - # # convert input - # cdef acb_ptr zvec - # zvec = _acb_vec_init(g) - # cdef long i - # for i in range(g): - # acb_set(zvec + i, acb_mat_entry(z.val, i, 0)) - # cdef slong nb_in = 1 - # cdef ulong ab = 0 - # cdef ulong all = True - # - # # initialize the output - # cdef slong nb = 1 << (2 * g) - # # 1. Calculate the length of the jet for one characteristic - # # This is the number of multi-indices (alpha) such that |alpha| < ord - # cdef slong nj = acb_theta_jet_len(g, ord) - # cdef acb_ptr theta = _acb_vec_init(nb) - # - # acb_theta_jet(theta, zvec, nb_in, tau.val, ord, ab, all, square, getprec()) - # _acb_vec_clear(zvec, g) - # # copy the output - # res = [] - # cdef acb r - # for i in range(nb): - # r = acb.__new__(acb) - # acb_set(r.val, theta + i) - # res.append(r) - # _acb_vec_clear(theta, nb) - # return acb_mat([res]) -def acb_theta_jet(acb_mat z, acb_mat tau, slong ord, ulong square=False): +def acb_theta_jets(acb_mat z, acb_mat tau, slong ord, ulong square=False): r""" Corrected wrapper for acb_theta_jet to handle multivariate Taylor expansions. """ - cdef slong g = tau.nrows() + g = tau.nrows() if g == 0: return [] # 1. Calculate the length of the jet for one characteristic # This is the number of multi-indices (alpha) such that |alpha| < ord - cdef slong nj = acb_theta_jet_len(g, ord) + cdef slong nj = acb_theta_jet_nb(g, ord) # 2. Total number of characteristics cdef slong nb = 1 << (2 * g) @@ -196,3 +152,49 @@ def acb_theta_jet(acb_mat z, acb_mat tau, slong ord, ulong square=False): _acb_vec_clear(theta, total_size) return res + + +#def acb_theta_jet(acb_mat z, acb_mat tau, slong ord, ulong square=False): + # r""" + # Computes derivatives of the vector valued Riemann theta function + # `(\theta_{a,b}(z, \tau) : a, b \in \{0,1\}^{g})` or its squares. + # + # This is a wrapper for the C-function + # `acb_theta_jet `_ + # and it follows the same conventions for the ordering of the theta characteristics. + # + # This should be used via the method :meth:`.acb_mat.theta`, explicitly ``tau.theta(z)``. + # """ + # g = tau.nrows() + # assert tau.ncols() == g + # assert z.nrows() == g + # assert z.ncols() == 1 + # + # # convert input + # cdef acb_ptr zvec + # zvec = _acb_vec_init(g) + # cdef long i + # for i in range(g): + # acb_set(zvec + i, acb_mat_entry(z.val, i, 0)) + # cdef slong nb_in = 1 + # cdef ulong ab = 0 + # cdef ulong all = True + # + # # initialize the output + # cdef slong nb = 1 << (2 * g) + # # 1. Calculate the length of the jet for one characteristic + # # This is the number of multi-indices (alpha) such that |alpha| < ord + # cdef slong nj = acb_theta_jet_len(g, ord) + # cdef acb_ptr theta = _acb_vec_init(nb) + # + # acb_theta_jet(theta, zvec, nb_in, tau.val, ord, ab, all, square, getprec()) + # _acb_vec_clear(zvec, g) + # # copy the output + # res = [] + # cdef acb r + # for i in range(nb): + # r = acb.__new__(acb) + # acb_set(r.val, theta + i) + # res.append(r) + # _acb_vec_clear(theta, nb) + # return acb_mat([res]) From cd11057443f4c0832052ad22d40a23e6e94e6c91 Mon Sep 17 00:00:00 2001 From: JHanselman Date: Wed, 6 May 2026 16:35:21 +0200 Subject: [PATCH 3/4] Removed nonsense --- src/flint/types/acb_mat.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flint/types/acb_mat.pyx b/src/flint/types/acb_mat.pyx index 8397a589..caf01287 100644 --- a/src/flint/types/acb_mat.pyx +++ b/src/flint/types/acb_mat.pyx @@ -838,7 +838,7 @@ cdef class acb_mat(flint_mat): from .acb_theta import acb_theta except ImportError: raise NotImplementedError("acb_mat.theta needs Flint >= 3.1.0") - return acb_theta(z, 2*tau, square=square) + return acb_theta(z, tau, square=square) def theta_jets(tau, z, ord, square=False): r""" From 22b4e5a2e43a97ee10d040e1f3cdbe11e0d14944 Mon Sep 17 00:00:00 2001 From: JHanselman Date: Wed, 13 May 2026 17:08:03 +0200 Subject: [PATCH 4/4] Add tests and docstring --- src/flint/test/test_acb_theta.py | 19 +++++++ src/flint/types/acb_mat.pyx | 4 +- src/flint/types/acb_theta.pyx | 85 ++++++++++++-------------------- 3 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/flint/test/test_acb_theta.py b/src/flint/test/test_acb_theta.py index 4ea6237a..c1470d8d 100644 --- a/src/flint/test/test_acb_theta.py +++ b/src/flint/test/test_acb_theta.py @@ -45,3 +45,22 @@ def test_acb_theta_shape_assertions() -> None: assert raises(lambda: acb_theta(object(), tau), TypeError) # type: ignore[arg-type] assert raises(lambda: acb_theta(z, object()), TypeError) # type: ignore[arg-type] + +def test_acb_theta_jets_basic() -> None: + if not _has_acb_theta(): + return + + from flint.types.acb_theta import acb_theta_jets + + z = acb(1 + 1j) + tau = acb(1.25 + 3j) + zmat = acb_mat([[z]]) + taumat = acb_mat([[tau]]) + ord = 2 + + direct = acb_theta_jets(zmat, taumat, ord) + via_method = taumat.theta_jets(zmat, ord) + assert is_close(direct, via_method, tol=1e-12, rel_tol=1e-12, max_width=1e-12) + assert direct.nrows() == 4 + assert direct.ncols() == 3 + diff --git a/src/flint/types/acb_mat.pyx b/src/flint/types/acb_mat.pyx index caf01287..0b67f2a4 100644 --- a/src/flint/types/acb_mat.pyx +++ b/src/flint/types/acb_mat.pyx @@ -840,7 +840,7 @@ cdef class acb_mat(flint_mat): raise NotImplementedError("acb_mat.theta needs Flint >= 3.1.0") return acb_theta(z, tau, square=square) - def theta_jets(tau, z, ord, square=False): + def theta_jets(tau, z, ord): r""" Computes Taylor approximation for the vector-valued Riemann theta function `(\theta_{a,b}(z, \tau) : a, b \in \{0,1\}^{g})` or its squares, @@ -857,4 +857,4 @@ cdef class acb_mat(flint_mat): from .acb_theta import acb_theta_jets except ImportError: raise NotImplementedError("acb_mat.theta needs Flint >= 3.1.0") - return acb_theta_jets(z, tau, ord, square=square) + return acb_theta_jets(z, tau, ord) diff --git a/src/flint/types/acb_theta.pyx b/src/flint/types/acb_theta.pyx index f615af89..cf3696db 100644 --- a/src/flint/types/acb_theta.pyx +++ b/src/flint/types/acb_theta.pyx @@ -97,26 +97,48 @@ def acb_theta(acb_mat z, acb_mat tau, ulong square=False): return acb_mat([res]) -def acb_theta_jets(acb_mat z, acb_mat tau, slong ord, ulong square=False): +def acb_theta_jets(acb_mat z, acb_mat tau, slong ord): r""" - Corrected wrapper for acb_theta_jet to handle multivariate Taylor expansions. + Computes the coefficients of the Taylor expansion of the vector valued Riemann + theta function `(\theta_{a,b}(z, \tau) : a, b \in \{0,1\}^{g})` or its squares. + + This is a wrapper for the C-function + `acb_theta_jet `_ + and it follows the same conventions for the ordering of the theta characteristics. + + This should be used via the method :meth:`.acb_mat.theta_jets`, explicitly ``tau.theta_jets(z, ord)``. + + >>> from flint import acb, acb_mat, showgood, ctx + >>> z = acb(1+1j); tau = acb(1.25+3j) + >>> acb_mat([[tau]]).theta_jets(acb_mat([[z]]),2) # doctest: +SKIP + [[0.969443038779670 +/- 5.67e-16] + [-0.0305569612081680 +/- 5.13e-17]j, + [-0.191993710594950 +/- 4.89e-16] + [0.191993710747776 +/- 7.42e-16]j, + [0.60317023860834 +/- 2.93e-15] + [0.60317023764810 +/- 4.86e-15]j] + [[1.03055696119601 +/- 3.89e-15] + [0.0305569612081680 +/- 5.13e-17]j, + [0.191993710594950 +/- 4.89e-16] + [-0.191993710442123 +/- 4.62e-16]j, + [-0.60317023668787 +/- 5.90e-15] + [-0.60317023764810 +/- 4.86e-15]j] + [[-1.22079026757697 +/- 4.36e-15] + [-1.82705551679115 +/- 5.17e-15]j, + [-5.71849316258739 +/- 7.02e-15] + [3.82088827346268 +/- 5.75e-15]j, + [6.0241074288587 +/- 3.88e-14] + [9.0163253443780 +/- 2.05e-14]j] + [[-1.82023591012499 +/- 2.67e-15] + [1.21625195015448 +/- 4.14e-15]j, + [3.8353056542516 +/- 4.99e-14] + [5.73981078971270 +/- 6.74e-15]j, + [8.9823364151977 +/- 2.44e-14] + [-6.0022138700195 +/- 3.72e-14]j] """ g = tau.nrows() if g == 0: return [] - # 1. Calculate the length of the jet for one characteristic + # Calculate the length of the jet for one characteristic # This is the number of multi-indices (alpha) such that |alpha| < ord cdef slong nj = acb_theta_jet_nb(g, ord) - # 2. Total number of characteristics + # Total number of characteristics cdef slong nb = 1 << (2 * g) - # 3. Total number of acb elements to allocate + # Total number of acb elements to allocate # FLINT stores nj coefficients for each of the nb characteristics cdef slong total_size = nb * nj - # Convert input z to acb_ptr cdef acb_ptr zvec = _acb_vec_init(g) cdef slong i, j for i in range(g): @@ -126,6 +148,7 @@ def acb_theta_jets(acb_mat z, acb_mat tau, slong ord, ulong square=False): cdef slong nb_in = 1 # Number of input z vectors cdef ulong ab = 0 # Base characteristic cdef ulong all = True # Compute all 2^2g characteristics + cdef ulong square = False # Don't compute the squares of the thetas. # Initialize the output buffer cdef acb_ptr theta = _acb_vec_init(total_size) @@ -134,7 +157,7 @@ def acb_theta_jets(acb_mat z, acb_mat tau, slong ord, ulong square=False): # Note: Computes all partial derivatives up to total order 'ord' acb_theta_jet(theta, zvec, nb_in, tau.val, ord, ab, all, square, getprec()) - # 4. Copy the output into a structured format + # Copy the output into a structured format # We return a list of lists: res[char_idx] = [coeff_0, coeff_1, ...] res = [] cdef acb r @@ -151,50 +174,4 @@ def acb_theta_jets(acb_mat z, acb_mat tau, slong ord, ulong square=False): _acb_vec_clear(zvec, g) _acb_vec_clear(theta, total_size) - return res - - -#def acb_theta_jet(acb_mat z, acb_mat tau, slong ord, ulong square=False): - # r""" - # Computes derivatives of the vector valued Riemann theta function - # `(\theta_{a,b}(z, \tau) : a, b \in \{0,1\}^{g})` or its squares. - # - # This is a wrapper for the C-function - # `acb_theta_jet `_ - # and it follows the same conventions for the ordering of the theta characteristics. - # - # This should be used via the method :meth:`.acb_mat.theta`, explicitly ``tau.theta(z)``. - # """ - # g = tau.nrows() - # assert tau.ncols() == g - # assert z.nrows() == g - # assert z.ncols() == 1 - # - # # convert input - # cdef acb_ptr zvec - # zvec = _acb_vec_init(g) - # cdef long i - # for i in range(g): - # acb_set(zvec + i, acb_mat_entry(z.val, i, 0)) - # cdef slong nb_in = 1 - # cdef ulong ab = 0 - # cdef ulong all = True - # - # # initialize the output - # cdef slong nb = 1 << (2 * g) - # # 1. Calculate the length of the jet for one characteristic - # # This is the number of multi-indices (alpha) such that |alpha| < ord - # cdef slong nj = acb_theta_jet_len(g, ord) - # cdef acb_ptr theta = _acb_vec_init(nb) - # - # acb_theta_jet(theta, zvec, nb_in, tau.val, ord, ab, all, square, getprec()) - # _acb_vec_clear(zvec, g) - # # copy the output - # res = [] - # cdef acb r - # for i in range(nb): - # r = acb.__new__(acb) - # acb_set(r.val, theta + i) - # res.append(r) - # _acb_vec_clear(theta, nb) - # return acb_mat([res]) + return acb_mat(res) \ No newline at end of file