unable to simplify a rather simple expression

67 views
Skip to first unread message

Undy

unread,
Dec 17, 2018, 4:07:56 PM12/17/18
to sympy
I have an expression (`expr`, see below) that I am unable to simplify in SymPy. For real and positive  `x`, `expr` is equivalent to `x**3 + 2*x`, but `simplify` and `refine` do not simplify the expression at all. (Mathematica does the simplification without any effort). How to simplify this expression with SymPy?

from sympy import *

x
= var('x')

expr
= 16*x**3/(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**2 - 2*2**(S(4)/5)*x*(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**(S(3)/5) + 10*x

expr1
= simplify(expr) # does nothing

expr2
= refine(expr, Q.positive(x)) # does nothing


r.du...@gmail.com

unread,
Dec 18, 2018, 12:04:34 PM12/18/18
to sy...@googlegroups.com
The problem is to force sympy simplyfing sqrt(x**4+4*x**2+4).

positive=True and factor at the good level work. The problem is that in my knowledge in sympy there is no built-in "apply a function f at all levels", so I used a loop over the levels from a high-enough on (5). I'd like to know if there are more elegant ways to proceed...

>>> x=Symbol("x",positive=True)
>>> expr = 16*x**3/(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**2 - 2*2**(S(4)/5
... )*x*(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**(S(3)/5) + 10*x
>>> e=expr
>>> for i in range(5,-1,-1): e=use(e,factor,i)
>>> e
x*(x**2 + 2)

ric

Aaron Meurer

unread,
Dec 18, 2018, 12:15:11 PM12/18/18
to sy...@googlegroups.com
factor(deep=True) is supposed to do this. However, for whatever
reason, it isn't applying to the subexpression.

You can do it manually using the bottom_up function, however (and also
as ric noted, you need to set x as positive). That is a more efficient
way than calling use() several times.

>>> x = symbols('x', positive=True)
>>> expr = 16*x**3/(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**2 - 2*2**(S(4)/5)*x*(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**(S(3)/5) + 10*x
>>> bottom_up(expr, factor)
x*(x**2 + 2)

Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
> To post to this group, send email to sy...@googlegroups.com.
> Visit this group at https://groups.google.com/group/sympy.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/930faa65-da6f-fe8f-db17-ab433bbd4632%40gmail.com.
> For more options, visit https://groups.google.com/d/optout.

r.du...@gmail.com

unread,
Dec 18, 2018, 2:28:30 PM12/18/18
to sy...@googlegroups.com
Happy to learn the existence of bottom_up :)

ric

PS: I'm wondering why such a useful function is not shown in the docs...

Undy

unread,
Dec 18, 2018, 2:55:52 PM12/18/18
to sympy
Good to know; thank you!

... but frankly I am a bit confused.
In this case, I knew what result to expect (thanks to Mathematica) and - with your help - I finally got it. The problem is, that this solution seems a little bit 'ad hoc' to me. What if I didn't know the result? I'd have probably assumed that the expression could not be meaningfully simplified. Is there a general strategy to use when I do not know the result in advance, and perhaps I do not even know if the simplification is feasible at all? (I mean without relying on Mathematica and possibly using documented functions/features.) 
Thanks!

Aaron Meurer

unread,
Dec 18, 2018, 6:44:24 PM12/18/18
to sy...@googlegroups.com
Ideally simplify() would have done the job for you. As I noted,
factor(deep=True) not working on this expression is a bug (I opened
https://github.com/sympy/sympy/issues/15669 for it).

However, note that in general, simplify() is heuristical, so there is
no guarantee that it will reduce an expression down to its "best"
form. But if you can see what sort of simplification operations need
to be applied, you can always apply them manually using the specific
simplification functions, along with utility functions like use() or
bottom_up().

Aaron Meurer
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/3444d024-9bdb-409b-94c7-7bcf4c4adcb3%40googlegroups.com.

r.du...@gmail.com

unread,
Dec 19, 2018, 6:54:31 AM12/19/18
to sy...@googlegroups.com
>Ideally simplify() would have done the job for you. As I noted,
>factor(deep=True) not working on this expression is a bug (I opened
>https://github.com/sympy/sympy/issues/15669 for it).

@Aaron
I'm not a python developer nor a sympy expert but I have the impression that the problem is due to the fact that
muladd = f.atoms(Mul,Add) [1]
lead to overlapping terms which conflict among them when doing xreplace two lines below. (Eliminating Mul might help reducing the overlaps...)

Example: deep works for expr but not for expr2 (which is x**3 * expr) due to the ordering of the overlapping terms

>>> expr = 1/(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**2
>>> expr.atoms(Mul,Add)
{-x**2, 8*x**2, x**2 - 2, 8*x**2 + (x**2 - 2)**2, -x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2}
>>> factor(expr,deep=True)
(-x**2 + sqrt((x**2 + 2)**2) + 2)**(-2)
>>> expr2 = x**3/(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**2
>>> factor(expr2,deep=True)
x**3/(x**2 - sqrt(x**4 + 4*x**2 + 4) - 2)**2
>>> expr2.atoms(Mul,Add)
{-x**2, 8*x**2, x**3/(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**2, x**2 - 2, 8*x**2 + (x**2 - 2)**2, -x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2}


The fix currently proposed in the PR [2] might work but does not seem to address this problem.

ric

PS I know I know I should open a github account... sorry for my laziness

[1]
https://github.com/sympy/sympy/blob/master/sympy/polys/polytools.py#L6322

[2]
https://github.com/sympy/sympy/issues/15669
Reply all
Reply to author
Forward
0 new messages