1919from collections .abc import Callable , Iterable
2020from dataclasses import dataclass
2121from functools import cache as _cache
22- from typing import cast
22+ from typing import TypeVar , cast
2323
2424import numpy as np
2525from numba import njit , prange
3333RealArray = NDArray [np .float64 ]
3434IntArray = 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
3749def 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# ---------------------------------------------------------------------------
6476def _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
6981def _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 )
108120def _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 )
197209def _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 )
247259def _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 )
299311def _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
0 commit comments