Amin Guermazi
Amin Guermazi

Reputation: 1732

Sympy `factor` and `simplify` not working properly?

Since I am working on a project involving square roots, I need square roots to be simplified to the max. However, some square roots expressions do not produce the disired result. Please consider checking this example:

>>> from sympy import * # just an example don't tell me that import * is obsolete
>>> x1 = simplify(factor(sqrt(3 + 2*sqrt(2))))
>>> x1 # notice that factoring doesn't work
sqrt(2*sqrt(2) + 3)
>>> x2 = sqrt(2) + 1
>>> x2 
sqrt(2) + 1
>>> x1 == x2
False
>>> N(x1)
2.41421356237309
>>> N(x2)
2.41421356237309
>>> N(x1) == N(x2)
True

As you can see, the numbers are actually equal, but numpy can't recognize that because it can't factorize and simplify x1. So how do I get the simplified form of x1 so that the equality would be correct without having to convert them to float ?

Thanks in advance.

Upvotes: 2

Views: 1280

Answers (2)

smichr
smichr

Reputation: 19047

When you are working with nested sqrt expressions, sqrtdenest is a good option to try. But a great fallback to use is nsimplify which can be more useful in some situations. Since this can give an answer that is not exactly the same as the input, I like to use this "safe" function to do the simplification:

def safe_nsimplify(x):
    from sympy import nsimplify
    if x.is_number:
        ns = nsimplify(x)
        if ns != x and x.equals(ns):
            return ns
    return x

>>> from sympy import sqrt, sqrtdenest
>>> eq = (-sqrt(2) + sqrt(10))/(2*sqrt(sqrt(5) + 5))
>>> simplify(eq)
(-sqrt(2) + sqrt(10))/(2*sqrt(sqrt(5) + 5))  <-- no change
>>> sqrtdenest(eq)
-sqrt(2)/(2*sqrt(sqrt(5) + 5)) + sqrt(10)/(2*sqrt(sqrt(5) + 5))  <-- worse
>>> safe_nsimplify(eq)
sqrt(1 - 2*sqrt(5)/5)  <-- better

On your expression

>>> safe_nsimplify(sqrt(2 * sqrt(2) + 3))
1 + sqrt(2)

And if you want to seek out such expressions wherever they occur in a larger expression you can use

>>> from sympy import bottom_up, tan
>>> bottom_up(tan(eq), safe_nsimplify)
tan(sqrt(1 - 2*sqrt(5)/5))

It might be advantageous to accept the result of sqrtdenest instead of using nsimplify as in

def safe_nsimplify(x):
  from sympy import nsimplify, sqrtdenest, Pow, S
  if x.is_number:
    if isinstance(x, Pow) and x.exp is S.Half:
        ns = sqrtdenest(x)
        if ns != x:
            return ns
    ns = nsimplify(x)
    if ns != x and x.equals(ns):
        return ns
  return x

Upvotes: 2

Amin Guermazi
Amin Guermazi

Reputation: 1732

Thanks to Oscar Benjamin, the function I was looking for was sqrtdenest:

>>> from sympy import *
>>> sqrtdenest(sqrt(2 * sqrt(2) + 3))
1 + sqrt(2)

I hope this answer would help other people

Upvotes: 1

Related Questions