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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions