Two rules in Simplify rewrite a power in a way that is only valid on part of the plane, and both change the value for real negative arguments. Measured on bcfefc26.
1. (x^n)^(1/m) collapses the exponents
"sqrt(x ^ 2)".Simplify() // x — it is abs(x)
"(x ^ 2) ^ (1/2)".Simplify() // x
"sqrt(x * x)".Simplify() // x
"(x ^ 2) ^ (1/2 - 2)".Simplify() // 1 / x ^ 3 — it is 1 / abs(x) ^ 3
"(x ^ 2) ^ (1/2 - 1)".Simplify() // 1 / x — it is 1 / abs(x)
At x = -0.63, sqrt(x^2) is 0.63 and the answer given is -0.63.
The rule is ({} ^ {}) ^ {} = {} ^ ({} * {}) in Patterns.PowerRules, applied unconditionally. (a^b)^c = a^(b*c) holds for a > 0, and for an even b with a fractional c it is exactly the case where it does not.
2. (-x)^(1/2) becomes i * sqrt(x)
"sqrt(-x)".Simplify() // i * sqrt(x)
"sqrt(-1 * x)".Simplify() // i * sqrt(x)
"sqrt(x / -1)".Simplify() // i * sqrt(x)
"(-x) ^ (1/2 - 1)".Simplify() // (-i) * x ^ (-1/2)
"(-x) ^ (1/2 - 2)".Simplify() // i * x ^ (-3/2)
At x = -0.63, sqrt(-x) is sqrt(0.63) = 0.7937… and i * sqrt(x) is i * (0.7937…i) = -0.7937….
sqrt(-z) = i*sqrt(z) holds off the negative real axis and fails on it, which is where a real negative x puts z.
Why they are one report
Both are the same trade: a rewrite that is true on the principal branch for positive arguments, applied without a condition. Whichever way this is settled — a domain condition on the rewrite, abs in the result, a codomain the rewrite can read, or a decision that AngouriMath simplifies as though every base were positive and says so — it should be settled once for both rather than patched separately.
It is worth noting what the library already does elsewhere, because the machinery exists: {}/{} simplifies to 1 provided not {} = 0, and log(a, a) to 1 provided a > 0. Attaching provided x >= 0 here is the same move. What it costs is that sqrt(x^2) stops being x for callers who were relying on it, and every such simplification starts printing a condition — the same trade recorded against the ln(a) + ln(b) = ln(a*b) rewrite, which is still formally unsound for the same reason and is tracked separately.
This is not new and not a regression. Both reproduce on 61af68a2 and before. Filing it because it had not been written down, not because something changed.
How it was found
By work/simpsweep, a harness that generates expressions to a bounded depth from a small alphabet, simplifies each, and compares the two forms numerically wherever both are defined and real. 10463 expressions, 31 disagreements: 30 of them are these two families, and the 31st is a plain sign error filed separately as #751.
The sweep uses negative sample points deliberately. A corpus evaluated only at positive points would find none of this, and work/propcheck — 151 hand-written expressions, all passing — is that corpus.
Two rules in
Simplifyrewrite a power in a way that is only valid on part of the plane, and both change the value for real negative arguments. Measured onbcfefc26.1.
(x^n)^(1/m)collapses the exponentsAt
x = -0.63,sqrt(x^2)is0.63and the answer given is-0.63.The rule is
({} ^ {}) ^ {} = {} ^ ({} * {})inPatterns.PowerRules, applied unconditionally.(a^b)^c = a^(b*c)holds fora > 0, and for an evenbwith a fractionalcit is exactly the case where it does not.2.
(-x)^(1/2)becomesi * sqrt(x)At
x = -0.63,sqrt(-x)issqrt(0.63) = 0.7937…andi * sqrt(x)isi * (0.7937…i) = -0.7937….sqrt(-z) = i*sqrt(z)holds off the negative real axis and fails on it, which is where a real negativexputsz.Why they are one report
Both are the same trade: a rewrite that is true on the principal branch for positive arguments, applied without a condition. Whichever way this is settled — a domain condition on the rewrite,
absin the result, a codomain the rewrite can read, or a decision that AngouriMath simplifies as though every base were positive and says so — it should be settled once for both rather than patched separately.It is worth noting what the library already does elsewhere, because the machinery exists:
{}/{}simplifies to1 provided not {} = 0, andlog(a, a)to1 provided a > 0. Attachingprovided x >= 0here is the same move. What it costs is thatsqrt(x^2)stops beingxfor callers who were relying on it, and every such simplification starts printing a condition — the same trade recorded against theln(a) + ln(b) = ln(a*b)rewrite, which is still formally unsound for the same reason and is tracked separately.This is not new and not a regression. Both reproduce on
61af68a2and before. Filing it because it had not been written down, not because something changed.How it was found
By
work/simpsweep, a harness that generates expressions to a bounded depth from a small alphabet, simplifies each, and compares the two forms numerically wherever both are defined and real. 10463 expressions, 31 disagreements: 30 of them are these two families, and the 31st is a plain sign error filed separately as #751.The sweep uses negative sample points deliberately. A corpus evaluated only at positive points would find none of this, and
work/propcheck— 151 hand-written expressions, all passing — is that corpus.