Search code examples
pythonsympysimplify

How to simplify expressions containing complex exponentials in Sympy


In a project I'm working on I'm dealing with expressions containing complex exponentials such as the one below, which I aim to simplify as much as possible:

from sympy import Rational, exp, I, pi, pretty, cos, sin

E = Rational(1,20) + (Rational(1,4) + exp(2*I*pi/5)/4)*exp(-4*I*pi/5)/5 + exp(-2*I*pi/5)/20 + (exp(4*I*pi/5)/4 + exp(2*I*pi/5)/4)*exp(2*I*pi/5)/5 + (exp(-2*I*pi/5)/4 + exp(-4*I*pi/5)/4)*exp(4*I*pi/5)/5 + (exp(-4*I*pi/5)/4 + exp(4*I*pi/5)/4)*exp(-2*I*pi/5)/5

print(pretty(E))

     ⎛     2⋅ⅈ⋅π⎞                       ⎛ 4⋅ⅈ⋅π    2⋅ⅈ⋅π⎞          ⎛ -2⋅ⅈ⋅π     -4⋅ⅈ⋅π ⎞          ⎛ -4⋅ⅈ⋅π     4⋅ⅈ⋅π⎞         
     ⎜     ─────⎟  -4⋅ⅈ⋅π               ⎜ ─────    ─────⎟  2⋅ⅈ⋅π   ⎜ ───────    ───────⎟  4⋅ⅈ⋅π   ⎜ ───────    ─────⎟  -2⋅ⅈ⋅π 
     ⎜       5  ⎟  ───────    -2⋅ⅈ⋅π    ⎜   5        5  ⎟  ─────   ⎜    5          5   ⎟  ─────   ⎜    5         5  ⎟  ───────
     ⎜1   ℯ     ⎟     5       ───────   ⎜ℯ        ℯ     ⎟    5     ⎜ℯ          ℯ       ⎟    5     ⎜ℯ          ℯ     ⎟     5   
     ⎜─ + ──────⎟⋅ℯ              5      ⎜────── + ──────⎟⋅ℯ        ⎜──────── + ────────⎟⋅ℯ        ⎜──────── + ──────⎟⋅ℯ       
1    ⎝4     4   ⎠            ℯ          ⎝  4        4   ⎠          ⎝   4          4    ⎠          ⎝   4         4   ⎠         
── + ───────────────────── + ──────── + ──────────────────────── + ──────────────────────────── + ────────────────────────────
20             5                20                 5                            5                              5              

I managed to simplify it a bit (mostly by trial-and-error using different functions described on https://docs.sympy.org/latest/modules/simplify/simplify.html):

E.rewrite(cos).expand().simplify()
-sqrt(-10 - 2*sqrt(5))/64 - sqrt(-10 + 2*sqrt(5))/64 + sqrt(-50 + 10*sqrt(5))/320 + 3*sqrt(-50 - 10*sqrt(5))/320

print(pretty(_))
    ____________     ____________     _____________       _____________
  ╲╱ -10 - 2⋅√5    ╲╱ -10 + 2⋅√5    ╲╱ -50 + 10⋅√5    3⋅╲╱ -50 - 10⋅√5 
- ────────────── - ────────────── + ─────────────── + ─────────────────
        64               64               320                320       

However, the resulting expression can still be simplified further, and in fact vanishes altogether — the question is how to do/show this in Sympy. I've tried using sqrtdenest to "denest" the square roots, but so far no luck.

Likewise, another expression rather similar to the first one simplifies to

print(pretty(-cos(pi/7)/7 - sin(pi/14)/7 + Rational(1,14) + sin(3*pi/14)/7))

     ⎛π⎞      ⎛π ⎞           ⎛3⋅π⎞
  cos⎜─⎟   sin⎜──⎟        sin⎜───⎟
     ⎝7⎠      ⎝14⎠   1       ⎝ 14⎠
- ────── - ─────── + ── + ────────
    7         7      14      7    

Again, this expression vanishes, though I'm not getting to that point in Sympy. Any directions on how to proceed would be most welcome.


Solution

  • Firstly the simplest check for situations like this is to use approximate numerical evaluation:

    In [2]: E.evalf()
    Out[2]: -0.e-130 - 0.e-132⋅ⅈ
    

    That strongly suggests that the result is zero.

    This is used internally by the nsimplify function:

    In [3]: nsimplify(E)
    Out[3]: 0
    

    Another way to verify that the expression is zero without approximation is to compute its minimal polynomial:

    In [4]: minpoly(E)
    Out[4]: x
    

    E must be a root of that polynomial and it only has one root (zero):

    In [5]: roots(_)
    Out[5]: {0: 1}
    

    This expression does seem to be particularly awkward for normal manipulation so many possible ways to simplify it don't seem to work. This one does though:

    In [25]: E.expand().rewrite(cos)
    Out[25]: 0
    

    I think that the main difficulty for most methods of simplification is the automatic evaluation of trig functions:

    In [34]: exp(2*I*pi/5).rewrite(cos)
    Out[34]: 
                     ________
      1   √5        ╱ √5   5 
    - ─ + ── + ⅈ⋅  ╱  ── + ─ 
      4   4      ╲╱   8    8 
    

    If we use symbols in place of numbers then we can prevent that:

    In [65]: En = E.subs(exp(2*I*pi/5), exp(n*I*pi/5))
    
    In [66]: En.rewrite(cos).simplify().subs(n, 2)
    Out[66]: 0