{"record":{"id":"a1d6b5422d26ef56","repo":"jax-ml/jax","slug":"negative-orders-for-normalization-is-not-implement","errorCode":null,"errorMessage":"Negative orders for normalization is not implemented yet.","messagePattern":"Negative orders for normalization is not implemented yet\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"jax/_src/scipy/special.py","lineNumber":2018,"sourceCode":"  Returns:\n    The 3D array representing the derivatives of associated Legendre functions\n    of the first kind.\n  \"\"\"\n\n  num_m, num_l, num_x = p.shape\n\n  # p_{l-1}^m.\n  p_m_lm1 = jnp.pad(p, ((0, 0), (1, 0), (0, 0)))[:, :num_l, :]\n\n  # p_{l-1}^{m+2}.\n  p_mp2_lm1 = jnp.pad(p_m_lm1, ((0, 2), (0, 0), (0, 0)))[2:num_m + 2, :, :]\n\n  # p_{l-1}^{m-2}.\n  p_mm2_lm1 = jnp.pad(p_m_lm1, ((2, 0), (0, 0), (0, 0)))[:num_m, :, :]\n\n  # Derivative computation requires negative orders.\n  if is_normalized:\n    raise NotImplementedError(\n        'Negative orders for normalization is not implemented yet.')\n  else:\n    if num_l > 1:\n      l_vec = jnp.arange(1, num_l - 1, dtype=x.dtype)\n      p_p1 = p[1, 1:num_l - 1, :]\n      coeff = -1.0 / ((l_vec + 1) * l_vec)\n      update_p_p1 = jnp_einsum.einsum('i,ij->ij', coeff, p_p1)\n      p_mm2_lm1 = p_mm2_lm1.at[1, 2:num_l, :].set(update_p_p1)\n\n    if num_l > 2:\n      l_vec = jnp.arange(2, num_l - 1, dtype=x.dtype)\n      p_p2 = p[2, 2:num_l - 1, :]\n      coeff = 1.0 / ((l_vec + 2) * (l_vec + 1) * l_vec * (l_vec - 1))\n      update_p_p2 = jnp_einsum.einsum('i,ij->ij', coeff, p_p2)\n      p_mm2_lm1 = p_mm2_lm1.at[0, 3:num_l, :].set(update_p_p2)\n\n  m_mat, l_mat = jnp.meshgrid(\n    jnp.arange(num_m, dtype=x.dtype),","sourceCodeStart":2000,"sourceCodeEnd":2036,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/scipy/special.py#L2000-L2036","documentation":"lpmn (associated Legendre functions) with is_normalized=True computes derivatives via _gen_derivatives, but the derivative recurrence requires negative orders, and normalized negative-order Legendre functions are not implemented in JAX. Hence the NotImplementedError.","triggerScenarios":"Calling jax.scipy.special.lpmn(m, n, z, is_normalized=True) with diff=True (the default), which routes into _gen_derivatives and hits the normalized branch.","commonSituations":"Porting scipy.special.lpmn-based geophysics or quantum mechanics code (spherical harmonics gradients) that uses normalized Legendre polynomials and their derivatives; gradient-based optimization over spherical-harmonic coefficients.","solutions":["Use is_normalized=False: lpmn(m, n, z, is_normalized=False, diff=True) works because the unnormalized branch implements negative orders","Normalize manually after computing unnormalized values/derivatives using known normalization factors","Compute gradients numerically (finite differences) for the normalized variant as a stopgap"],"exampleFix":"// before\np, dp = jax.scipy.special.lpmn(m, n, z, is_normalized=True)  # diff default\n// after\np, dp = jax.scipy.special.lpmn(m, n, z, is_normalized=False)\n# apply normalization factors yourself if needed","handlingStrategy":"fallback","validationCode":"if is_normalized and diff:\n    use_is_normalized = False  # fall back to unnormalized + manual normalization","typeGuard":null,"tryCatchPattern":"try:\n    p, dp = lpmn(m, n, z, is_normalized=True)\nexcept NotImplementedError:\n    p, dp = lpmn(m, n, z, is_normalized=False)\n    p, dp = normalize(p), normalize(dp)","preventionTips":["Check the JAX feature matrix for lpmn before relying on normalized derivatives","Wrap lpmn in a helper that documents supported (is_normalized, diff) combinations"],"tags":["jax","scipy-special","legendre","not-implemented","spherical-harmonics"],"backgroundTag":"feature-not-implemented","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}