jax-ml/jax · error · ValueError

jnp.unwrap does not support complex inputs.

Error message

jnp.unwrap does not support complex inputs.

What it means

jnp.unwrap reconstructs a real phase signal by removing discontinuities larger than discont. Phase math has no meaning for complex arrays, so complex inputs are rejected.

Source

Thrown at jax/_src/numpy/lax_numpy.py:3852

    The first few values match the input angle ``theta`` above, but after this the
    values are wrapped because the ``sin`` and ``cos`` observations obscure the phase
    information. The purpose of the :func:`unwrap` function is to recover the original
    signal from this wrapped view of it:

    >>> jnp.unwrap(theta_out, period=360)
    Array([ 76., 133., 179., 203., 230., 233., 239., 240., 255., 328., 386.,
           468., 513., 567., 654., 719., 775., 823., 873., 957.],      dtype=float32)

    It does this by assuming that the true underlying sequence does not differ by more than
    ``discont`` (which defaults to ``period / 2``) within a single step, and when it encounters
    a larger discontinuity it adds factors of the period to the data. For periodic signals
    that satisfy this assumption, :func:`unwrap` can recover the original phased signal.
  """
  p = util.ensure_arraylike("unwrap", p)
  p, period = util.promote_dtypes(p, period)

  if issubdtype(p.dtype, np.complexfloating):
    raise ValueError("jnp.unwrap does not support complex inputs.")
  if p.shape[axis] == 0:
    return p

  if discont is None:
    discont = period / 2
  if dtypes.issubdtype(p.dtype, np.integer):
    interval = period // 2
  else:
    interval = period / 2

  dd = diff(p, axis=axis)
  ddmod = ufuncs.mod(dd + interval, period) - interval
  ddmod = where((ddmod == -interval) & (dd > 0), interval, ddmod)

  ph_correct = where(ufuncs.abs(dd) < discont, 0, ddmod - dd)

  up = concatenate((
    lax_slicing.slice_in_dim(p, 0, 1, axis=axis),

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Take the real part: jnp.unwrap(jnp.real(p)) or jnp.angle(p) for complex phases
  2. Cast dtype: p.astype(jnp.float32)
  3. Check period: pass a real-valued period to avoid complex promotion

Example fix

// before
phase_unwrapped = jnp.unwrap(hilbert_out)  # complex
// after
phase_unwrapped = jnp.unwrap(jnp.angle(hilbert_out))
Defensive patterns

Strategy: type-guard

Validate before calling

if jnp.iscomplexobj(p):
    p = jnp.angle(p)  # or jnp.real(p)

Type guard

def is_real_phase(a) -> bool:
    return not jnp.iscomplexobj(a)

Prevention

When it happens

Trigger: jnp.unwrap(jnp.array([0.1+0j, 6.2+0j])) — even complex arrays with zero imaginary parts, because promotion made the dtype complex.

Common situations: Unwrapping phases from FFT or analytic-signal pipelines (hilbert transform output) where dtype is complex; accidental complex promotion from a complex period argument.

Related errors


AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27). Data as JSON: /api/errors/8bca81354a941b5b. Report an issue: GitHub.