{"record":{"id":"aaa7f8a6ca6537e5","repo":"jax-ml/jax","slug":"rel-entr-does-not-support-complex-valued-inputs","errorCode":null,"errorMessage":"rel_entr does not support complex-valued inputs.","messagePattern":"rel_entr does not support complex-valued inputs\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/scipy/special.py","lineNumber":1212,"sourceCode":"       p\\log(p/q) & p>0,q>0\\\\\n       0 & p=0,q\\ge 0\\\\\n       \\infty & \\mathrm{otherwise}\n    \\end{cases}\n\n  Args:\n    p: arraylike, real-valued.\n    q: arraylike, real-valued.\n\n  Returns:\n    array of relative entropy values.\n\n  See also:\n    - :func:`jax.scipy.special.entr`\n    - :func:`jax.scipy.special.kl_div`\n  \"\"\"\n  p, q = promote_args_inexact(\"rel_entr\", p, q)\n  if dtypes.issubdtype(p.dtype, np.complexfloating):\n    raise ValueError(\"rel_entr does not support complex-valued inputs.\")\n  zero = _lax_const(p, 0.0)\n  both_gt_zero_mask = lax.bitwise_and(lax.gt(p, zero), lax.gt(q, zero))\n  one_zero_mask = lax.bitwise_and(lax.eq(p, zero), lax.ge(q, zero))\n\n  safe_p = jnp.where(both_gt_zero_mask, p, 1)\n  safe_q = jnp.where(both_gt_zero_mask, q, 1)\n  log_val = lax.sub(_xlogx(safe_p), xlogy(safe_p, safe_q))\n  result = jnp.where(\n      both_gt_zero_mask, log_val, jnp.where(one_zero_mask, zero, np.inf)\n  )\n  return result\n\n# coefs of (2k)! / B_{2k} where B are bernoulli numbers\n# those numbers are obtained using https://www.wolframalpha.com\n_BERNOULLI_COEFS = np.array([\n    12,\n    -720,\n    30240,","sourceCodeStart":1194,"sourceCodeEnd":1230,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/scipy/special.py#L1194-L1230","documentation":"jax.scipy.special.rel_entr (relative entropy / x*log(x/y)) raises ValueError on complex p after promotion, since its masked select logic (both_gt_zero_mask etc.) relies on real comparisons that are undefined for complex numbers.","triggerScenarios":"Calling rel_entr(p, q) with complex p (or promoting to complex because one operand is complex); also reached indirectly via kl_div(p, q) with complex inputs.","commonSituations":"Divergence losses in VAE/RL training where parameters or reconstructions became complex; debugging kl_div errors that surface from this inner rel_entr call; mixing complex-valued targets into probability computations.","solutions":["Pass real probabilities: rel_entr(jnp.real(p), jnp.real(q))","Audit the loss pipeline for accidental complex dtype (check .dtype of every intermediate with jax.debug.print)","If this fires from kl_div, fix the complex inputs to kl_div — rel_entr is the caller's callee"],"exampleFix":"// before\njax.scipy.special.rel_entr(p, q)  # p is complex\n// after\njax.scipy.special.rel_entr(jnp.real(p), jnp.real(q))","handlingStrategy":"validation","validationCode":"if np.issubdtype(jnp.result_type(p, q), np.complexfloating):\n    p, q = jnp.real(p), jnp.real(q)","typeGuard":"def promotion_is_real(p, q):\n    return not np.issubdtype(jnp.result_type(p, q), np.complexfloating)","tryCatchPattern":null,"preventionTips":["Remember kl_div complex errors originate here in rel_entr — fix at the kl_div call site","Check jnp.result_type of operand pairs before special functions"],"tags":["jax","scipy-special","relative-entropy","complex-dtype"],"backgroundTag":"unsupported-complex-input","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}