user3208693
user3208693

Reputation: 23

Sympy comparison fail with sympified expressions

I recently encountered a problem with SympPy that I can't fix ; I'm a beginner with the library and I've spent quite some time looking for a solution on the web, without finding one, which is why I came here.

Here's the problem : I have an output from a javascript web app that gives me the expression (x**2)**(1/3) instead of x**(2/3). "No problem", I thought, "SymPy's going to parse that"... except not. If I compare, I get that result:

>>> sympify("(x**2)**(1/3)") == sympify("x**(2/3)")
False

I ran some tests, and I only get that with exponents in sympified expressions. Example:

>>> (x**(1/3))**2 == x**(2/3)
True

Even weirder, if I invert the two exponents, I get a correct result:

>>> sympify("(x**(1/3))**2") == sympify("x**(2/3)")
True

I tried using simplify and extend, but it's not working either. The only way I could get a good result is by using eval, but that requires to first create a symbol "x", which is something I cannot do, because I can't know exactly which symbols are going to be used in the expressions.

So here's the question : is that a bug in SymPy, or am I doing something wrong?

Please excuse me if the issue is well known and I couldn't find anything about it by myself.

Upvotes: 2

Views: 481

Answers (2)

asmeurer
asmeurer

Reputation: 91470

As pointed out on the SymPy issue, this is intentional. These two expressions are not equal for general complex x. Take for instance x = -1, ((-1)**2)**(1/3) == 1**(1/3) == 1, whereas (-1)**(2/3) = -1/2 + sqrt(3)/2*I. See http://docs.sympy.org/0.7.3/tutorial/simplification.html#powers for more information. SymPy will only simplify such exponents if it knows that it is true for the full domain.

In particular, this is true if x is nonnegative. (x**a)**b == x**(a*b) is also true if b is an integer, which is why your other tests worked.

If you want to force simplify this, there are two main options. One (the best option), is to just assume that x is nonegative, or positive.

>>> x = symbols('x', positive=True)
>>> (x**2)**(S(1)/3)
x**(2/3)

If you want to replace your symbols with positive versions after parsing from a string, you can use posify:

>>> posify((x**2)**(S(1)/3))
(_x**(2/3), {_x: x})

Or you can use the locals argument to sympify to manually set {'x': Symbol('x', positive=True}.

Another way, if this doesn't fully suit your needs, is to force simplify it with powdenest:

>>> x = symbols('x') # No assumptions on x
>>> (x**2)**(S(1)/3)
(x**2)**(1/3)
>>> powdenest((x**2)**(S(1)/3), force=True)
x**(2/3)

If you do this, you need to be careful, because you are applying identities that are not always true, so you can end up with mathematically incorrect results.

Upvotes: 1

aterrel
aterrel

Reputation: 2082

It's a bug in sympy.

There is not a correct expand for a hierarchy of exponentials (see https://github.com/sympy/sympy/blob/master/sympy/core/power.py#L445)

Upvotes: 0

Related Questions