Skip to content

degree_jacobi_anger_approximation returns wrong degree at moderate t with loose precision #1848

Description

@gnperdue

There is a bug in qualtran/linalg/polynomial/jacobi_anger_approximations.py. |J_n(t)| for n < t oscillates and crosses zero many times before asymptotic decay. The library function assumes monotone behavior in n, but it isn't monotonic in this region. As such bisect_left lands on the wrong zero.

The bug is in 59–65 of jacobi_anger_approximations.py:

d = 1
while not term_too_small(d):
    d *= 2
d = bisect.bisect_left(range(d), True, key=term_too_small) - 1

The doubling loop exits at the first d within epsilon, but that can be a zero crossing in the oscillating region. It can be seen by running the test (jacobi_anger_approximations_test.py) body with different params:

import numpy as np
from qualtran.linalg.polynomial.jacobi_anger_approximations import (
    approx_exp_cos_by_jacobi_anger,
    degree_jacobi_anger_approximation,
)

t = 50.0
precision = 1e-2

degree = degree_jacobi_anger_approximation(t, precision=precision)
print(f"degree = {degree}")

random_state = np.random.RandomState(42 + int(t))
P = np.polynomial.Polynomial(approx_exp_cos_by_jacobi_anger(t, degree=degree))
theta = 2 * np.pi * random_state.random(1000)
e_itheta = np.exp(1j * theta)
np.testing.assert_allclose(
    P(e_itheta) * e_itheta ** (-degree),
    np.exp(1j * t * np.cos(theta)),
    rtol=precision * 2,
)

The fix would scan monotonically past the oscillating region.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions