最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How to cancel trigonometric expressions in SymPy - Stack Overflow

programmeradmin1浏览0评论

I have a bunch of expressions deque([-6*cos(th)**3 - 9*cos(th), (11*cos(th)**2 + 4)*sin(th), -6*sin(th)**2*cos(th), sin(th)**3]).

Then I run them through some code that iteratively takes a derivative, adds, and then divides by sin(th):

import sympy as sp
th = sp.symbols('th')
order = 4

for nu in range(order + 1, 2*order): # iterate order-1 more times to reach the constants
    q = 0
    for mu in range(1, nu): # Terms come from the previous derivative, so there are nu - 1 of them here.
        p = exprs.popleft()
        term = q + sp.diff(p, th)
        exprs.append(sp.cancel(term/sp.sin(th)))
        q = p
    exprs.append(sp.cancel(q/sp.sin(th)))
    print(nu, exprs)

The output is a bunch of junk:

5 deque([18*cos(th)**2 + 9, (-22*sin(th)**2*cos(th) + 5*cos(th)**3 - 5*cos(th))/sin(th), 6*sin(th)**2 - cos(th)**2 + 4, -3*sin(th)*cos(th), sin(th)**2])
6 deque([-36*cos(th), (22*sin(th)**4 - 19*sin(th)**2*cos(th)**2 + 14*sin(th)**2 - 5*cos(th)**4 + 5*cos(th)**2)/sin(th)**3, (-8*sin(th)**2*cos(th) + 5*cos(th)**3 - 5*cos(th))/sin(th)**2, (9*sin(th)**2 - 4*cos(th)**2 + 4)/sin(th), -cos(th), sin(th)])
7 deque([36, (24*sin(th)**4*cos(th) + 39*sin(th)**2*cos(th)**3 - 24*sin(th)**2*cos(th) + 15*cos(th)**5 - 15*cos(th)**3)/sin(th)**5, (30*sin(th)**4 - 34*sin(th)**2*cos(th)**2 + 19*sin(th)**2 - 15*cos(th)**4 + 15*cos(th)**2)/sin(th)**4, (9*sin(th)**2*cos(th) + 9*cos(th)**3 - 9*cos(th))/sin(th)**3, (10*sin(th)**2 - 4*cos(th)**2 + 4)/sin(th)**2, 0, 1])

I expect the formulas to become simpler over the time steps and end up as a bunch of constants. Here's a correct output:

5 deque([9*cos(2*th) + 18, -27*sin(2*th)/2, 7*sin(th)**2 + 3, -3*sin(2*th)/2, sin(th)**2])
6 deque([-36*cos(th), 36*sin(th), -13*cos(th), 13*sin(th), -cos(th), sin(th)])
7 deque([36, 0, 49, 0, 14, 0, 1])

I can add various .simplify() calls and get it to work for order = 4, but I'm trying to get it to work with more complicated expressions with higher orders, and I'm finding SymPy is just not reliably figuring out how to cancel a sin(th) at each stage (even though I know it's possible to do so). How can I coax it in the right direction?

I'm finding .trigsimp() and .simplify() sometimes create factors of higher frequency, like sin(2th), and then .cancel() can't figure out how to eliminate a lower-frequency sin(th) from those. Yet if I don't simplify at all, or try to simplify only at the end, sympy does markedly worse, both in terms of runtime and final complexity.

Here are the expression deques for higher orders. The example above comes from order 4 only for the sake of simplicity while explaining the setup. The real problem is that I can't find a solution that works beyond order 6. I'd like a solution that works on all of these:

  • 5: deque([-24*cos(th)**4 - 72*cos(th)**2 - 9, (50*cos(th)**3 + 55*cos(th))*sin(th), (-35*cos(th)**2 - 10)*sin(th)**2, 10*sin(th)**3*cos(th), -sin(th)**4])
  • 6: deque([-120*cos(th)**5 - 600*cos(th)**3 - 225*cos(th), (274*cos(th)**4 + 607*cos(th)**2 + 64)*sin(th), (-225*cos(th)**3 - 195*cos(th))*sin(th)**2, (85*cos(th)**2 + 20)*sin(th)**3, -15*sin(th)**4*cos(th), sin(th)**5])
  • 7: deque([-720*cos(th)**6 - 5400*cos(th)**4 - 4050*cos(th)**2 - 225, (1764*cos(th)**5 + 6552*cos(th)**3 + 2079*cos(th))*sin(th), (-1624*cos(th)**4 - 2842*cos(th)**2 - 259)*sin(th)**2, (735*cos(th)**3 + 525*cos(th))*sin(th)**3, (-175*cos(th)**2 - 35)*sin(th)**4, 21*sin(th)**5*cos(th), -sin(th)**6])
  • 8: deque([-5040*cos(th)**7 - 52920*cos(th)**5 - 66150*cos(th)**3 - 11025*cos(th), (13068*cos(th)**6 + 73188*cos(th)**4 + 46575*cos(th)**2 + 2304)*sin(th), (-13132*cos(th)**5 - 38626*cos(th)**3 - 10612*cos(th))*sin(th)**2, (6769*cos(th)**4 + 9772*cos(th)**2 + 784)*sin(th)**3, (-1960*cos(th)**3 - 1190*cos(th))*sin(th)**4, (322*cos(th)**2 + 56)*sin(th)**5, -28*sin(th)**6*cos(th), sin(th)**7])

If you're curious where these come from, you can see my full notebook here, which is part of a larger project with a lot of math.

I have a bunch of expressions deque([-6*cos(th)**3 - 9*cos(th), (11*cos(th)**2 + 4)*sin(th), -6*sin(th)**2*cos(th), sin(th)**3]).

Then I run them through some code that iteratively takes a derivative, adds, and then divides by sin(th):

import sympy as sp
th = sp.symbols('th')
order = 4

for nu in range(order + 1, 2*order): # iterate order-1 more times to reach the constants
    q = 0
    for mu in range(1, nu): # Terms come from the previous derivative, so there are nu - 1 of them here.
        p = exprs.popleft()
        term = q + sp.diff(p, th)
        exprs.append(sp.cancel(term/sp.sin(th)))
        q = p
    exprs.append(sp.cancel(q/sp.sin(th)))
    print(nu, exprs)

The output is a bunch of junk:

5 deque([18*cos(th)**2 + 9, (-22*sin(th)**2*cos(th) + 5*cos(th)**3 - 5*cos(th))/sin(th), 6*sin(th)**2 - cos(th)**2 + 4, -3*sin(th)*cos(th), sin(th)**2])
6 deque([-36*cos(th), (22*sin(th)**4 - 19*sin(th)**2*cos(th)**2 + 14*sin(th)**2 - 5*cos(th)**4 + 5*cos(th)**2)/sin(th)**3, (-8*sin(th)**2*cos(th) + 5*cos(th)**3 - 5*cos(th))/sin(th)**2, (9*sin(th)**2 - 4*cos(th)**2 + 4)/sin(th), -cos(th), sin(th)])
7 deque([36, (24*sin(th)**4*cos(th) + 39*sin(th)**2*cos(th)**3 - 24*sin(th)**2*cos(th) + 15*cos(th)**5 - 15*cos(th)**3)/sin(th)**5, (30*sin(th)**4 - 34*sin(th)**2*cos(th)**2 + 19*sin(th)**2 - 15*cos(th)**4 + 15*cos(th)**2)/sin(th)**4, (9*sin(th)**2*cos(th) + 9*cos(th)**3 - 9*cos(th))/sin(th)**3, (10*sin(th)**2 - 4*cos(th)**2 + 4)/sin(th)**2, 0, 1])

I expect the formulas to become simpler over the time steps and end up as a bunch of constants. Here's a correct output:

5 deque([9*cos(2*th) + 18, -27*sin(2*th)/2, 7*sin(th)**2 + 3, -3*sin(2*th)/2, sin(th)**2])
6 deque([-36*cos(th), 36*sin(th), -13*cos(th), 13*sin(th), -cos(th), sin(th)])
7 deque([36, 0, 49, 0, 14, 0, 1])

I can add various .simplify() calls and get it to work for order = 4, but I'm trying to get it to work with more complicated expressions with higher orders, and I'm finding SymPy is just not reliably figuring out how to cancel a sin(th) at each stage (even though I know it's possible to do so). How can I coax it in the right direction?

I'm finding .trigsimp() and .simplify() sometimes create factors of higher frequency, like sin(2th), and then .cancel() can't figure out how to eliminate a lower-frequency sin(th) from those. Yet if I don't simplify at all, or try to simplify only at the end, sympy does markedly worse, both in terms of runtime and final complexity.

Here are the expression deques for higher orders. The example above comes from order 4 only for the sake of simplicity while explaining the setup. The real problem is that I can't find a solution that works beyond order 6. I'd like a solution that works on all of these:

  • 5: deque([-24*cos(th)**4 - 72*cos(th)**2 - 9, (50*cos(th)**3 + 55*cos(th))*sin(th), (-35*cos(th)**2 - 10)*sin(th)**2, 10*sin(th)**3*cos(th), -sin(th)**4])
  • 6: deque([-120*cos(th)**5 - 600*cos(th)**3 - 225*cos(th), (274*cos(th)**4 + 607*cos(th)**2 + 64)*sin(th), (-225*cos(th)**3 - 195*cos(th))*sin(th)**2, (85*cos(th)**2 + 20)*sin(th)**3, -15*sin(th)**4*cos(th), sin(th)**5])
  • 7: deque([-720*cos(th)**6 - 5400*cos(th)**4 - 4050*cos(th)**2 - 225, (1764*cos(th)**5 + 6552*cos(th)**3 + 2079*cos(th))*sin(th), (-1624*cos(th)**4 - 2842*cos(th)**2 - 259)*sin(th)**2, (735*cos(th)**3 + 525*cos(th))*sin(th)**3, (-175*cos(th)**2 - 35)*sin(th)**4, 21*sin(th)**5*cos(th), -sin(th)**6])
  • 8: deque([-5040*cos(th)**7 - 52920*cos(th)**5 - 66150*cos(th)**3 - 11025*cos(th), (13068*cos(th)**6 + 73188*cos(th)**4 + 46575*cos(th)**2 + 2304)*sin(th), (-13132*cos(th)**5 - 38626*cos(th)**3 - 10612*cos(th))*sin(th)**2, (6769*cos(th)**4 + 9772*cos(th)**2 + 784)*sin(th)**3, (-1960*cos(th)**3 - 1190*cos(th))*sin(th)**4, (322*cos(th)**2 + 56)*sin(th)**5, -28*sin(th)**6*cos(th), sin(th)**7])

If you're curious where these come from, you can see my full notebook here, which is part of a larger project with a lot of math.

Share Improve this question edited Feb 3 at 19:05 Pavel Komarov asked Feb 1 at 0:00 Pavel KomarovPavel Komarov 1,24617 silver badges35 bronze badges 2
  • Hello, there is a bounty in this question, but you already accepted an answer? – Davide_sd Commented Feb 3 at 22:11
  • He was quick, thankfully. – Pavel Komarov Commented Feb 4 at 0:51
Add a comment  | 

1 Answer 1

Reset to default 2 +50

Rewriting to exp and doing the simplifications seems to work in this case:

from collections import deque
from sympy import *
import sympy as sp
th = sp.symbols('th')
order = 4
exprs = deque([i.simplify() for i in [-6*cos(th)**3 - 9*cos(th), (11*cos(th)**2 + 4)*sin(th), -6*sin(th)**2*cos(th), sin(th)**3]])

def simpler(e):
    return e.rewrite(exp).simplify().rewrite(cos).cancel()

for nu in range(order + 1, 2*order): # iterate order-1 more times to reach the constants
    q = 0
    for mu in range(1, nu): # Terms come from the previous derivative, so there are nu - 1 of them here.
        p = exprs.popleft()
        term = q + sp.diff(p, th)
        exprs.append(simpler(term/sp.sin(th)))
        q = p
    this = simpler(q/sp.sin(th))
    exprs.append(this)
    print(nu,exprs)

outputs

5 deque([9*cos(2*th) + 18, -27*cos(2*th - pi/2)/2, 13/2 - 7*cos(2*th)/2, -3*cos(2*th - pi/2)/2, cos(th - pi/2)**2])
6 deque([-36*cos(th), 36*sin(th), -13*cos(th), 13*sin(th), -cos(th), cos(th - pi/2)])
7 deque([36, 0, 49, 0, 14, 0, 1])

If you just want to get the constants at the end, don't simplify until the end. Here is a complete working example:

from collections import deque
import sympy as sp
th = sp.symbols('th')
E = {4:deque([-6*cos(th)**3 - 9*cos(th), (11*cos(th)**2 + 4)*sin(th), -6*sin(th)**2*cos(th), sin(th)**3]),
5: deque([-24*cos(th)**4 - 72*cos(th)**2 - 9, (50*cos(th)**3 + 55*cos(th))*sin(th), (-35*cos(th)**2 - 10)*sin(th)**2, 10*sin(th)**3*cos(th), -sin(th)**4]),
6: deque([-120*cos(th)**5 - 600*cos(th)**3 - 225*cos(th), (274*cos(th)**4 + 607*cos(th)**2 + 64)*sin(th), (-225*cos(th)**3 - 195*cos(th))*sin(th)**2, (85*cos(th)**2 + 20)*sin(th)**3, -15*sin(th)**4*cos(th), sin(th)**5]),
7: deque([-720*cos(th)**6 - 5400*cos(th)**4 - 4050*cos(th)**2 - 225, (1764*cos(th)**5 + 6552*cos(th)**3 + 2079*cos(th))*sin(th), (-1624*cos(th)**4 - 2842*cos(th)**2 - 259)*sin(th)**2, (735*cos(th)**3 + 525*cos(th))*sin(th)**3, (-175*cos(th)**2 - 35)*sin(th)**4, 21*sin(th)**5*cos(th), -sin(th)**6]),
8:  deque([-5040*cos(th)**7 - 52920*cos(th)**5 - 66150*cos(th)**3 - 11025*cos(th), (13068*cos(th)**6 + 73188*cos(th)**4 + 46575*cos(th)**2 + 2304)*sin(th), (-13132*cos(th)**5 - 38626*cos(th)**3 - 10612*cos(th))*sin(th)**2, (6769*cos(th)**4 + 9772*cos(th)**2 + 784)*sin(th)**3, (-1960*cos(th)**3 - 1190*cos(th))*sin(th)**4, (322*cos(th)**2 + 56)*sin(th)**5, -28*sin(th)**6*cos(th), sin(th)**7])}
from time import time
for order in E:
 t=time()
 exprs = E[order]
 for nu in range(order + 1, 2*order): # iterate order-1 more times to reach the constants
    q = 0
    for mu in range(1, nu): # Terms come from the previous derivative, so there are nu - 1 of them here.
        p = exprs.popleft()
        term = q + sp.diff(p, th)
        exprs.append(sp.cancel(term/sp.sin(th)))
        q = p
    exprs.append(sp.cancel(q/sp.sin(th)))
 t1=time()-t
 t=time()
 print(order,round(t1,2),[i.rewrite(sp.exp).simplify() for i in exprs],round(time()-t,2))

4 0.06 [36, 0, 49, 0, 14, 0, 1] 0.16
5 0.13 [-576, 0, -820, 0, -273, 0, -30, 0, -1] 0.4
6 0.29 [14400, 0, 21076, 0, 7645, 0, 1023, 0, 55, 0, 1] 0.68
7 0.59 [-518400, 0, -773136, 0, -296296, 0, -44473, 0, -3003, 0, -91, 0, -1] 1.14
8 0.97 [25401600, 0, 38402064, 0, 15291640, 0, 2475473, 0, 191620, 0, 7462, 0, 140, 0, 1] 1.7
发布评论

评论列表(0)

  1. 暂无评论