The quotient half of #801, split out because fixing it costs answers rather than only shapes, and which way to go is a call for the maintainers rather than for me.
Patterns.PowerRules gathers a quotient of powers unconditionally:
Divf(Powf(var any1, var any3), Powf(var any2, var any3a)) when any3 == any3a => new Powf(any1 / any2, any3),
(a/b)^n = a^n / b^n needs arg(a) - arg(b) to stay inside (-pi, pi], and for real bases of opposite sign it does not:
sqrt(2) / sqrt(-3) = 1.41421 / 1.73205i = -0.8165i
(2 / -3) ^ (1/2) = (-0.66667) ^ (1/2) = +0.8165i
The product form of the same identity is fixed in #801. This one is not, and the reason is measured rather than assumed.
What guarding it costs
Applying the same guard the product form now carries -- fire for a whole exponent, or for two decidably positive bases -- breaks twelve tests, and two of them are answers rather than shapes:
(x ^ 2 + 1) ^ x / (x ^ 2) ^ x limit x -> +oo 1 -> no longer answered
(x ^ 3 + 1) ^ x / (x ^ 3) ^ x limit x -> +oo 1 -> no longer answered
That is the whole point of #740: the limit machinery reads a 1^oo off a single power and cannot see one in a quotient, so gathering is what makes those answerable at all. casbench stays at 113/117 and every generated harness stays clean, so the cost is confined to that -- but it is a real cost.
The bases in those cases (x^2, x^2 + 1) are non-negative for every real x, so the gathering is sound there. It is only not decidably so, which is why a guard written in terms of Evaled is Real { IsPositive: true } throws them out along with the genuinely unsound ones.
The options, as I see them
- Leave it. The wrong answer needs two bases of opposite sign under a fractional exponent, which is rare next to the limits that would be lost.
- Guard it and lose those limits, then win them back by teaching the gathering to see that
x^2 and x^2 + 1 are non-negative -- a sign analysis the library does not have today.
- Guard it under
MathS.Settings.Codomain, so a real codomain keeps gathering and a complex one does not. This is the case section 12 of work/TRIAGE.md predicted the codomain would eventually be needed for.
Recorded in PowerProductBranchTest.TheQuotientFormIsStillWrongAndThatIsRecorded, which asserts the disagreement rather than the agreement -- so on the day this is fixed that test fails and points here.
The quotient half of #801, split out because fixing it costs answers rather than only shapes, and which way to go is a call for the maintainers rather than for me.
Patterns.PowerRulesgathers a quotient of powers unconditionally:(a/b)^n = a^n / b^nneedsarg(a) - arg(b)to stay inside(-pi, pi], and for real bases of opposite sign it does not:The product form of the same identity is fixed in #801. This one is not, and the reason is measured rather than assumed.
What guarding it costs
Applying the same guard the product form now carries -- fire for a whole exponent, or for two decidably positive bases -- breaks twelve tests, and two of them are answers rather than shapes:
That is the whole point of #740: the limit machinery reads a
1^oooff a single power and cannot see one in a quotient, so gathering is what makes those answerable at all.casbenchstays at 113/117 and every generated harness stays clean, so the cost is confined to that -- but it is a real cost.The bases in those cases (
x^2,x^2 + 1) are non-negative for every realx, so the gathering is sound there. It is only not decidably so, which is why a guard written in terms ofEvaled is Real { IsPositive: true }throws them out along with the genuinely unsound ones.The options, as I see them
x^2andx^2 + 1are non-negative -- a sign analysis the library does not have today.MathS.Settings.Codomain, so a real codomain keeps gathering and a complex one does not. This is the case section 12 ofwork/TRIAGE.mdpredicted the codomain would eventually be needed for.Recorded in
PowerProductBranchTest.TheQuotientFormIsStillWrongAndThatIsRecorded, which asserts the disagreement rather than the agreement -- so on the day this is fixed that test fails and points here.