Skip to content

Simplify returns the negation of the right answer for k*a/a^(1/n) #751

Description

@Rafael-SOWNet

Simplify returns the negation of the right answer for a quotient of powers of the same base whose exponents leave a positive fractional remainder. Measured on bcfefc26:

"2 * a / sqrt(a)".Simplify()      // (-2) * sqrt(a) provided not a = 0
"a * 2 / a ^ (1/2)".Simplify()    // the same
"a * 3 / a ^ (1/2)".Simplify()    // (-3) * sqrt(a) provided not a = 0
"a ^ 3 * 2 / a ^ (1/2)".Simplify()// (-2) * a ^ (5/2) provided not a = 0
"a * 2 / a ^ (1/3)".Simplify()    // (-2) * a ^ (2/3) provided not a = 0
"a * 2 / a ^ (1/4)".Simplify()    // (-2) * a ^ (3/4) provided not a = 0

2a/√a is 2√a. At a = 1.7 the expression is 2.6076809620810594… and the answer given is -2.6076809620810594….

There is no branch question here: a is positive at the point measured, every power is real, and the magnitude is right. Only the sign is wrong.

Where the boundary is

The coefficient's own sign is flipped, whichever it is:

a * (-2) / a ^ (1/2)   ->   2 * sqrt(a) provided not a = 0     also wrong
a * (1/2) / a ^ (1/2)  ->   -1/2 * sqrt(a) provided not a = 0

Neighbouring shapes that are correct, which is what narrows it:

a / sqrt(a)            ->   a / sqrt(a)        unchanged, correct
a * 2 / a              ->   2 provided not a = 0
a * 2 / a ^ 2          ->   2 / a
a * 2 / a ^ (3/2)      ->   unchanged                     (the remainder is negative)
(a * 2) * a ^ (-1/2)   ->   2 * sqrt(a)                   correct — written as a product
2 * sqrt(a) * sqrt(a)  ->   2 * a

So it needs all three of: a numeric coefficient, a division (the same expression written as multiplication by a negative power is right), and a remaining exponent that is positive and fractional.

What has been ruled out

  • Not NumericNeatRules. That is where the sibling defect Simplify inverts a quotient whose denominator has a negative factor #715 lived — two rules that read a negative constant out of a numerator, copy-edited from four where doing so is right. Disabling the whole rule set leaves this unchanged.
  • Not the radical rationalisation. RootExtraction.PullOutOfDenominator is guarded on a Rational radicand and never sees a variable base.
  • Not sqrt(a) * sqrt(a). That gives a, correctly, so the numerator is not being rewritten wrongly on the way.

The provided not a = 0 in the answer says that one of the (a * c) / c rules in Patterns.CommonRules fired, so the shape does reach the cancellation — the question is what hands it a negated coefficient first, and Simplify chooses among candidates by a complexity metric, so a wrong candidate need only be the shortest to win. That is exactly how #715 presented.

How it was found

By work/simpsweep, a new 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, of which this is the only one that is not a branch-cut question (see the sibling issue).

The point of generating rather than listing: work/propcheck asks this same property of 151 hand-written expressions and finds nothing, because nobody writing a corpus writes a * 2 / a ^ (1/2). #715 was found by tracing a NaN limit, and #744 by generating polynomials — neither by a corpus.

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