Skip to content

a^n / b^n is gathered into (a/b)^n unconditionally, which is wrong for bases of opposite sign #802

Description

@Rafael-SOWNet

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

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions