You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
That is quite a vague and ambiguous topic when it comes to computational algebra. As we know, n-th root is something whose n-th power is the root's argument. So technically there are a lot of such numbers. The simplest way to represent a root is fractioned powers, e. g. square root of x is x^(1/2).
There we come to another problem: we know that (x ^ a) ^ b = x ^ (a * b), and we know, that 1/2 * 2 = 1. So technically we get that sqrt(x^2) = x which is actually okay to me, but in most common cases it won't be accepted. Reason: principle root.
There're more ambiguous stuff, I might add some more info to this issue. Any thoughts are welcomed and may be discussed in this thread.
Some measurements for the thread, since the ambiguity is easier to argue about with the current behaviour written down. master at a45a7256, default codomain (complex).
written
node
Simplify
Evaled
sqrt(x)
Powf
sqrt(x)
sqrt(x)
x ^ (1/2)
Powf
sqrt(x)
sqrt(x)
sqrt(x ^ 2)
Powf
sqrt(x ^ 2)
sqrt(x ^ 2)
(x ^ 2) ^ (1/2)
Powf
sqrt(x ^ 2)
sqrt(x ^ 2)
sqrt(-1)
Powf
i
i
(-8) ^ (1/3)
Powf
-2
-2
The library already made the choice this issue is about, in the direction the issue prefers. There is no root node — sqrt(x)isPowf(x, 1/2) — and sqrt(x ^ 2) is not simplified to x. So (x^a)^b = x^(a*b) is not applied unconditionally, which is the guard against the principal-root problem in the body.
(-8) ^ (1/3) = -2 is worth noting as the one that will surprise: the real cube root rather than the principal complex one, which is 1 + i*sqrt(3). That is a deliberate-looking choice and it is inconsistent with sqrt(-1) = i taking the principal branch. If any single thing here deserves an issue of its own, I think it is that pair.
sqrt(x) and x ^ (1/2) are not structurally equal, though they simplify alike — and the cost models rank them differently:
model
sqrt(x)
x ^ (1/2)
Default
10.000
13.000
SmallestTree
3.000
5.000
FewestRadicals
1.003
1.005
Both are counted as one radical by FewestRadicals — that is right, and it is right only since #953, which taught the feature models to read the exponent's value rather than its written node (#950). Before that, an exponent written as 2 ^ (-1) was not seen as a radical at all.
So the practical state is: one representation, two spellings, ranked by size rather than by kind, and no unconditional exponent-merging rule. The remaining ambiguity is the branch question — which root x ^ (1/n) denotes for negative x — and that is where MathS.Settings.Codomain already carries a decision the rules can consult, as Logf now does since #916.
This really needs an escalation to whether we need a dedicated node for the radical sign (presumably yes because the selection of principal root that is implied by the surd). Part of v3 redesign
Another instance, from the integrator. Measured on master acd4702:
value
(-3.35)^(-18/5)
0.012877… (real root)
(-3.35)^(-3/10) * (-3.35)^(-33/10)
0.003979… + 0.012247…i (principal)
The exponents sum to -18/5, so x^a x^b = x^(a+b) fails at a negative base once one exponent has an odd denominator and the others don't. The integrator gathers powers of one base when it normalises an integrand. So (d + k x)^(-3 - 2p) (d + k x)^p (a k + c d x)^p is answered as if it were (d + k x)^(-3 - p) (a k + c d x)^p, which is exact for a symbolic p. After substituting p = 3/10 and x = -0.7 the derivative of that answer is no longer the integrand, because (d + k x)^(-18/5) is now evaluated as a real root. With p = 1/3, p = -7/4 or a symbolic p it agrees.
Two data points for this, from the upper incomplete gamma function (#2077, #2078).
The real root has a bound.Number.Pow takes the real root only for an exact exponent whose denominator is below 10, because that is where its root search stops. (-8)^(1/3) is -2, but (-8)^(1/11) takes the principal branch. SimplificationContract §6's table says "odd denominator" and does not mention the bound.
A function that takes the principal branch now meets it.gamma(a, z) takes the principal branch of z^a, as mpmath's gammainc and Mathematica's Gamma[a, z] do. Its derivative -z^(a - 1) e^(-z) goes through the power. So at a negative z, with a an exact rational of odd denominator below 10, the evaluated derivative is not the derivative of the value. At a = 2/5, z = -17/15, the function's value has imaginary part -3.667, while z^(-3/5) in the derivative is real.
Either reading would make the two agree, if it held everywhere. Today the node follows the references and documents the mismatch (MathS.IncompleteGamma, from #2078).
A correction to my comment above. Keeping gamma(a, z) on the principal branch was wrong, and the node now takes the power's branch instead (PR to follow, from the-incomplete-gamma-function-takes-the-powers-branch).
The mismatch was not only between a derivative and a value. Every antiderivative written in the function inherits it. With the next integration rule, ∫₁² e^(x^3) dx came out as (gamma(1/3, -8) - gamma(1/3, -1))/3 = -137.76 + …i. Quadrature gives 275.51, the same number turned by e^(-2iπ/3). Differentiating the antiderivative back matched the integrand, because the symbolic derivative takes the real root consistently, so the corpus harness could not see it.
Gamma(a, z) = Gamma(a) - z^a g(a, z) with g entire, so taking z^a from the power is one factor, (-1)^p e^(-iπp/q) on the cut. gamma(1/3, -2) is then real, 10.2125…, matching DLMF 8.7.3's sum with the real root at 90 digits. The function and its derivative then agree wherever the power does. Whichever way this issue is decided, the node should follow the power. It now does, so a change to the power carries it along.
Activity
Rafael-SOWNet commentedon Aug 16, 2026
Some measurements for the thread, since the ambiguity is easier to argue about with the current behaviour written down.
masterata45a7256, default codomain (complex).SimplifyEvaledsqrt(x)Powfsqrt(x)sqrt(x)x ^ (1/2)Powfsqrt(x)sqrt(x)sqrt(x ^ 2)Powfsqrt(x ^ 2)sqrt(x ^ 2)(x ^ 2) ^ (1/2)Powfsqrt(x ^ 2)sqrt(x ^ 2)sqrt(-1)Powfii(-8) ^ (1/3)Powf-2-2The library already made the choice this issue is about, in the direction the issue prefers. There is no root node —
sqrt(x)isPowf(x, 1/2)— andsqrt(x ^ 2)is not simplified tox. So(x^a)^b = x^(a*b)is not applied unconditionally, which is the guard against the principal-root problem in the body.(-8) ^ (1/3) = -2is worth noting as the one that will surprise: the real cube root rather than the principal complex one, which is1 + i*sqrt(3). That is a deliberate-looking choice and it is inconsistent withsqrt(-1) = itaking the principal branch. If any single thing here deserves an issue of its own, I think it is that pair.sqrt(x)andx ^ (1/2)are not structurally equal, though they simplify alike — and the cost models rank them differently:sqrt(x)x ^ (1/2)DefaultSmallestTreeFewestRadicalsBoth are counted as one radical by
FewestRadicals— that is right, and it is right only since #953, which taught the feature models to read the exponent's value rather than its written node (#950). Before that, an exponent written as2 ^ (-1)was not seen as a radical at all.So the practical state is: one representation, two spellings, ranked by size rather than by kind, and no unconditional exponent-merging rule. The remaining ambiguity is the branch question — which root
x ^ (1/n)denotes for negativex— and that is whereMathS.Settings.Codomainalready carries a decision the rules can consult, asLogfnow does since #916.The kernel's dependency list is held to by a test (#1181)
Happypig375 commentedon Sep 18, 2026
This really needs an escalation to whether we need a dedicated node for the radical sign (presumably yes because the selection of principal root that is implied by the surd). Part of v3 redesign
Happypig375 commentedon Sep 27, 2026
Assigning goal type with the central design question being the above comment
Rafael-SOWNet commentedon Oct 14, 2026
Another instance, from the integrator. Measured on master acd4702:
(-3.35)^(-18/5)0.012877…(real root)(-3.35)^(-3/10) * (-3.35)^(-33/10)0.003979… + 0.012247…i(principal)The exponents sum to
-18/5, sox^a x^b = x^(a+b)fails at a negative base once one exponent has an odd denominator and the others don't. The integrator gathers powers of one base when it normalises an integrand. So(d + k x)^(-3 - 2p) (d + k x)^p (a k + c d x)^pis answered as if it were(d + k x)^(-3 - p) (a k + c d x)^p, which is exact for a symbolicp. After substitutingp = 3/10andx = -0.7the derivative of that answer is no longer the integrand, because(d + k x)^(-18/5)is now evaluated as a real root. Withp = 1/3,p = -7/4or a symbolicpit agrees.Rafael-SOWNet commentedon Oct 22, 2026
Two data points for this, from the upper incomplete gamma function (#2077, #2078).
The real root has a bound.
Number.Powtakes the real root only for an exact exponent whose denominator is below 10, because that is where its root search stops.(-8)^(1/3)is-2, but(-8)^(1/11)takes the principal branch. SimplificationContract §6's table says "odd denominator" and does not mention the bound.A function that takes the principal branch now meets it.
gamma(a, z)takes the principal branch ofz^a, as mpmath'sgammaincand Mathematica'sGamma[a, z]do. Its derivative-z^(a - 1) e^(-z)goes through the power. So at a negativez, withaan exact rational of odd denominator below 10, the evaluated derivative is not the derivative of the value. Ata = 2/5,z = -17/15, the function's value has imaginary part-3.667, whilez^(-3/5)in the derivative is real.Either reading would make the two agree, if it held everywhere. Today the node follows the references and documents the mismatch (
MathS.IncompleteGamma, from #2078).🤖 Generated with Claude Code
https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
Integrate the upper incomplete gamma function beside a power or a pol…
Rafael-SOWNet commentedon Oct 22, 2026
A correction to my comment above. Keeping
gamma(a, z)on the principal branch was wrong, and the node now takes the power's branch instead (PR to follow, fromthe-incomplete-gamma-function-takes-the-powers-branch).The mismatch was not only between a derivative and a value. Every antiderivative written in the function inherits it. With the next integration rule,
∫₁² e^(x^3) dxcame out as(gamma(1/3, -8) - gamma(1/3, -1))/3 = -137.76 + …i. Quadrature gives 275.51, the same number turned bye^(-2iπ/3). Differentiating the antiderivative back matched the integrand, because the symbolic derivative takes the real root consistently, so the corpus harness could not see it.Gamma(a, z) = Gamma(a) - z^a g(a, z)withgentire, so takingz^afrom the power is one factor,(-1)^p e^(-iπp/q)on the cut.gamma(1/3, -2)is then real,10.2125…, matching DLMF 8.7.3's sum with the real root at 90 digits. The function and its derivative then agree wherever the power does. Whichever way this issue is decided, the node should follow the power. It now does, so a change to the power carries it along.🤖 Generated with Claude Code
https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
Take the power's branch in the incomplete gamma function (#2080)
Take the real root in the sampled checks where the library's power ta…