Skip to content

Commit 2f7a83f

Browse files
committed
Fix strict mypy compatibility for numba and array typing
1 parent ac66394 commit 2f7a83f

2 files changed

Lines changed: 24 additions & 21 deletions

File tree

src/quantumhall_matrixelements/exchange_laguerre.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from collections.abc import Callable, Iterable
2020
from dataclasses import dataclass
2121
from functools import cache as _cache
22-
from typing import cast
22+
from typing import TypeVar, cast
2323

2424
import numpy as np
2525
from numba import njit, prange
@@ -33,6 +33,18 @@
3333
RealArray = NDArray[np.float64]
3434
IntArray = NDArray[np.int64]
3535

36+
_NumbaFunc = TypeVar("_NumbaFunc", bound=Callable[..., object])
37+
38+
39+
def _typed_njit(
40+
*, parallel: bool = False, fastmath: bool = False
41+
) -> Callable[[_NumbaFunc], _NumbaFunc]:
42+
"""Type-preserving wrapper around ``numba.njit`` for strict mypy."""
43+
return cast(
44+
"Callable[[_NumbaFunc], _NumbaFunc]",
45+
njit(parallel=parallel, fastmath=fastmath),
46+
)
47+
3648

3749
def cartesian_to_polar(Gxy: RealArray) -> tuple[RealArray, RealArray]:
3850
"""Convert (nG,2) Cartesian G vectors to (|G|, theta)."""
@@ -63,7 +75,7 @@ def _legendre_q_nodes_weights(N: int, qmax: float) -> tuple[RealArray, RealArray
6375
# ---------------------------------------------------------------------------
6476
def _ogata_psi(t: RealArray) -> RealArray:
6577
"""Ogata's double-exponential map psi(t) = t * tanh((pi/2) sinh t)."""
66-
return cast(RealArray, t * np.tanh(0.5 * np.pi * np.sinh(t)))
78+
return np.asarray(t * np.tanh(0.5 * np.pi * np.sinh(t)), dtype=np.float64)
6779

6880

6981
def _ogata_dpsi(t: RealArray) -> RealArray:
@@ -104,7 +116,7 @@ def _ogata_q_nodes(nu: int, h: float, N: int) -> tuple[RealArray, RealArray]:
104116
return x.astype(np.float64), series_fac.astype(np.float64)
105117

106118

107-
@njit(fastmath=False) # type: ignore[misc]
119+
@_typed_njit(fastmath=False)
108120
def _precompute_R_table(q_nodes: RealArray, logfact: RealArray) -> RealArray:
109121
"""Compute R[iq, n, m] such that F_{n,m}(q,phi)=phase*R[iq,n,m]."""
110122
Nq = q_nodes.size
@@ -193,7 +205,7 @@ def _build_phase_tables(
193205
return phase_in, phase_out
194206

195207

196-
@njit(parallel=True, fastmath=False) # type: ignore[misc]
208+
@_typed_njit(parallel=True, fastmath=False)
197209
def _exchange_fock_numba(
198210
rho: ComplexArray,
199211
R: RealArray,
@@ -243,7 +255,7 @@ def _exchange_fock_numba(
243255
return F
244256

245257

246-
@njit(parallel=True, fastmath=False) # type: ignore[misc]
258+
@_typed_njit(parallel=True, fastmath=False)
247259
def _evaluate_exchange_kernels_laguerre_numba(
248260
R: RealArray,
249261
w_eff: RealArray,
@@ -295,7 +307,7 @@ def _evaluate_exchange_kernels_laguerre_numba(
295307
return out
296308

297309

298-
@njit(fastmath=False, parallel=True) # type: ignore[misc]
310+
@_typed_njit(fastmath=False, parallel=True)
299311
def _ogata_q_evaluate_numba(
300312
x_nodes: RealArray,
301313
w_eff: RealArray,
@@ -440,9 +452,7 @@ def exchange_fock(self, rho: ComplexArray) -> ComplexArray:
440452
)
441453

442454
rho_c = np.ascontiguousarray(rho)
443-
F = cast(
444-
ComplexArray,
445-
_exchange_fock_numba(
455+
F = _exchange_fock_numba(
446456
rho_c,
447457
self.R,
448458
self.w_eff,
@@ -451,7 +461,6 @@ def exchange_fock(self, rho: ComplexArray) -> ComplexArray:
451461
self.phase_out,
452462
self.max_d,
453463
self.max_order,
454-
),
455464
)
456465

457466
return -F if self.include_minus else F
@@ -653,9 +662,7 @@ def get_exchange_kernels_laguerre(
653662

654663
kernels = _precompute_bessel_table(G_gl, q_nodes, max_order)
655664

656-
vals_gl = cast(
657-
ComplexArray,
658-
_evaluate_exchange_kernels_laguerre_numba(
665+
vals_gl = _evaluate_exchange_kernels_laguerre_numba(
659666
R,
660667
w_eff,
661668
kernels,
@@ -667,8 +674,7 @@ def get_exchange_kernels_laguerre(
667674
sel_m2.astype(np.int64, copy=False),
668675
max_d,
669676
max_order,
670-
),
671-
)
677+
)
672678
values[gl_idx, :] = vals_gl
673679

674680
# --- Ogata q-space path (for |G| >= kmin_ogata) ---
@@ -718,9 +724,7 @@ def get_exchange_kernels_laguerre(
718724
float(kappa) * sf * x_nodes[None, :] / (k_col**2 * 2.0 * np.pi)
719725
).astype(np.float64)
720726

721-
vals_og = cast(
722-
ComplexArray,
723-
_ogata_q_evaluate_numba(
727+
vals_og = _ogata_q_evaluate_numba(
724728
x_nodes,
725729
w_eff_og,
726730
k_og,
@@ -732,8 +736,7 @@ def get_exchange_kernels_laguerre(
732736
pi_og,
733737
po_og,
734738
max_d,
735-
),
736-
)
739+
)
737740
values[np.ix_(og_idx, entry_idx)] = vals_og
738741

739742
# Note: sign_magneticfield is already incorporated in the phase tables

src/quantumhall_matrixelements/exchange_ogata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def _legendre_nodes_weights_mapped(nquad: int, scale: float) -> tuple[RealArray,
5555
# -----------------------------------------------------------------------------
5656
def _ogata_psi(t: RealArray) -> RealArray:
5757
"""Ogata's double-exponential map ψ(t) = t * tanh((π/2) sinh t)."""
58-
return cast(RealArray, t * np.tanh(0.5 * np.pi * np.sinh(t)))
58+
return np.asarray(t * np.tanh(0.5 * np.pi * np.sinh(t)), dtype=np.float64)
5959

6060

6161
def _ogata_dpsi(t: RealArray) -> RealArray:

0 commit comments

Comments
 (0)