{"record":{"id":"bcbf6fe062cf1400","repo":"jax-ml/jax","slug":"expn-does-not-support-complex-valued-inputs","errorCode":null,"errorMessage":"expn does not support complex-valued inputs.","messagePattern":"expn does not support complex-valued inputs\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/scipy/special.py","lineNumber":2965,"sourceCode":"\n  .. math::\n\n     \\mathrm{expn}(n, x) = E_n(x) = x^{n-1}\\int_x^\\infty\\frac{e^{-t}}{t^n}\\mathrm{d}t\n\n  Args:\n    n: arraylike, real-valued\n    x: arraylike, real-valued\n\n  Returns:\n    array of expn values\n\n  See also:\n    - :func:`jax.scipy.special.expi`\n    - :func:`jax.scipy.special.exp1`\n  \"\"\"\n  n, x = promote_args_inexact(\"expn\", n, x)\n  if dtypes.issubdtype(x.dtype, np.complexfloating):\n    raise ValueError(\"expn does not support complex-valued inputs.\")\n  _c = _lax_const\n  zero = _c(x, 0)\n  one = _c(x, 1)\n  conds = [\n    (n < _c(n, 0)) | (x < zero),\n    (x == zero) & (n < _c(n, 2)),\n    (x == zero) & (n >= _c(n, 2)),\n    (n == _c(n, 0)) & (x >= zero),\n    (n >= _c(n, 5000)),\n    (x > one),\n  ]\n  n1 = jnp.where(n == _c(n, 1), n + n, n)\n  vals = [\n    np.nan,\n    np.inf,\n    one / n1,  # prevent div by zero\n    jnp.exp(-x) / x,\n    _expn3,","sourceCodeStart":2947,"sourceCodeEnd":2983,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/scipy/special.py#L2947-L2983","documentation":"jax.scipy.special.expn (generalized exponential integral En) rejects complex x after promotion via promote_args_inexact. Its piecewise branch structure (small-x series vs continued fraction) is implemented only for real floats.","triggerScenarios":"Calling jax.scipy.special.expn(n, x) with complex x; transitively, any complex input to exp1 (which calls expn(1, x)) also raises here.","commonSituations":"Complex-argument E_n integrals in physics code; passing complex values to exp1 expecting SciPy semantics where scipy.special.expn supports complex inputs.","solutions":["For E1 of complex argument use mpmath.e1 or scipy on the host via jax.pure_callback.","For real pipelines, ensure upstream ops (fft, casts) have not promoted x to complex (e.g. use jnp.real(x) if imaginary parts are numerically zero).","Check x.dtype in debug runs to find where the promotion to complex happens."],"exampleFix":"# before (raises)\ny = jax.scipy.special.expn(2, x)  # x complex\n\n# after: strip spurious imaginary part or use host SciPy\ny = jax.scipy.special.expn(2, jnp.real(x)) if jnp.allclose(x.imag, 0) else \\\n    jax.pure_callback(lambda v: scipy.special.expn(2, v), x.real.dtype, x)","handlingStrategy":"type-guard","validationCode":"x = jnp.asarray(x)\nif dtypes.issubdtype(x.dtype, jnp.complexfloating):\n    if jnp.allclose(x.imag, 0):\n        x = x.real\n    else:\n        raise TypeError('expn is real-only in JAX')","typeGuard":"def coerce_real_if_imaginary_zero(x):\n    x = jnp.asarray(x)\n    if dtypes.issubdtype(x.dtype, jnp.complexfloating) and np.allclose(x.imag, 0):\n        return x.real\n    return x","tryCatchPattern":"try:\n    y = jax.scipy.special.expn(n, x)\nexcept ValueError:\n    y = jax.pure_callback(lambda a: scipy.special.expn(n, a), x.real.dtype, x)","preventionTips":["Trace dtype promotion in pipelines that mix fft with special functions.","Centralize expn/exp1/expi calls in one module with dtype guards."],"tags":["jax","expn","complex-numbers","unsupported-dtype","exponential-integral"],"backgroundTag":"complex-input-unsupported","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}