繁体   English   中英

SymPy无法解决三角方程组

[英]SymPy unable to solve a system of trigonometric equations

我正在尝试让SymPy解决方程组,但这给了我一个错误:

NotImplementedError: could not solve 3*sin(3*t0/2)*tan(t0) + 2*cos(3*t0/2) - 4

我还有另一种方法可以求解方程组:

sin(x)+(y-x)cos(x)           = 0

-1.5(y-x)sin(1.5x)+cos(1.5x) = 2

我用了 :

from sympy import *
solve([sin(x)+(y-x)cos(x), -1.5(y-x)sin(1.5x)+cos(1.5x)-2], x, y)

SymPy可以用此方程做得更好,但最终它等于约10次多项式,其根只能抽象地表示。 我将描述一个人可以采取的步骤,并展示SymPy可以走多远。 这是一个半手动的解决过程,应该更加自动化。

首先,不要在方程式中放入1.5或其他浮点数。 相反,引入系数a = Rational(3, 2)并使用该系数:

eq = [sin(x) + (y-x)*cos(x), -a*(y-x)*sin(a*x) + cos(a*x) - 2]

可以使用第一个等式y=x-tan(x)来消除变量y,这对我们来说很容易看到,但是SymPy有时会错失良机。 让我们来帮助它:

eq1 = eq[1].subs(y, x-tan(x))   #   3*sin(3*x/2)*tan(x)/2 + cos(3*x/2) - 2

solveset ,由于不同参数的三角函数的这种混合,所以solvesolveset (替代的SymPy解算器)放弃了方程式。 我们中有些人记得在上学的时候,三角函数可以表示为半参数切线的有理函数,所以让我们这样做:用tan重写方程。

eq2 = eq1.rewrite(tan)   #   (-tan(3*x/4)**2 + 1)/(tan(3*x/4)**2 + 1) - 2 + 3*tan(3*x/4)*tan(x)/(tan(3*x/4)**2 + 1)

如前所述,这使论点减半。 在trig函数中具有x / 4之类的分数是不好的。 引入一个新符号var('u') ,并使u = x / 4:

eq3 = eq2.subs(x, 4*u)   #   (-tan(3*u)**2 + 1)/(tan(3*u)**2 + 1) - 2 + 3*tan(3*u)*tan(4*u)/(tan(3*u)**2 + 1)

现在,我们可以使用expand_trig根据tan(u)扩展所有这些切线。 等式变得更长:

eq4 = expand_trig(eq3)  #  (1 - (-tan(u)**3 + 3*tan(u))**2/(-3*tan(u)**2 + 1)**2)/(1 + (-tan(u)**3 + 3*tan(u))**2/(-3*tan(u)**2 + 1)**2) - 2 + 3*(-4*tan(u)**3 + 4*tan(u))*(-tan(u)**3 + 3*tan(u))/((1 + (-tan(u)**3 + 3*tan(u))**2/(-3*tan(u)**2 + 1)**2)*(-3*tan(u)**2 + 1)*(tan(u)**4 - 6*tan(u)**2 + 1))

但这也更简单,因为tan(u)可以看作另一个未知数,例如v

eq5 = eq4.subs(tan(u), v)  #  (1 - (-v**3 + 3*v)**2/(-3*v**2 + 1)**2)/(1 + (-v**3 + 3*v)**2/(-3*v**2 + 1)**2) - 2 + 3*(-4*v**3 + 4*v)*(-v**3 + 3*v)/((1 + (-v**3 + 3*v)**2/(-3*v**2 + 1)**2)*(-3*v**2 + 1)*(v**4 - 6*v**2 + 1))

太好了,现在我们有一个合理的功能。 可以使用solveset(eq5, x) 默认情况下, solveset提供所有复杂的解决方案,并且我们只需要其中的真实根,因此让我们将域指定为Reals:

vsol = list(solveset(eq5, v, domain=S.Reals))

这些没有代数公式,因此将它们抽象地记录下来,但是这些是我们可以使用的实际数字:

[CRootOf(3*v**10 + 9*v**8 - 78*v**6 + 22*v**4 - 21*v**2 + 1, 0),
 CRootOf(3*v**10 + 9*v**8 - 78*v**6 + 22*v**4 - 21*v**2 + 1, 1),
 CRootOf(3*v**10 + 9*v**8 - 78*v**6 + 22*v**4 - 21*v**2 + 1, 2),
 CRootOf(3*v**10 + 9*v**8 - 78*v**6 + 22*v**4 - 21*v**2 + 1, 3)]

例如,我们现在可以回到x和y并评估解决方案:

xsol = [4*atan(v) for v in vsol] 
ysol = [x - tan(x) for x in xsol]
numsol = [(N(x), N(y)) for x, y in zip(xsol, ysol)]

数值为

[(-4.35962510714700, -1.64344290066272),
 (-0.877886785847899, 0.326585146723377),
 (0.877886785847899, -0.326585146723377),
 (4.35962510714700, 1.64344290066272)]

当然,由于切线是周期性的,因此存在无限多个。 最后,让我们检查一下它们是否有效:

residuals = [[e.subs({x: xv, y: yv}) for e in eq] for xv, yv in numsol]

这些是1e-15或更小的一堆数字,所以是的,等式在机器精度内。

与我们从SciPy或其他数字求解器获得的纯数字解决方案不同,可以在不重复任何过程的情况下以任意精度对它们进行评估。 例如,第一个x解的50位数字:

xsol[0].evalf(50)  #   -4.3596251071470021258397061103704574594477338857831

只是为了好玩,这里是一个手动解决方案,只需要解决5级多项式:

写出t = x/2a = yxs = sin tc = cos tS = sin xC = cos x

给定的方程式可以重写

(1)  2 sc + a (c^2 - s^2) = 0
(2)  3 a s^3 - 9 a c^2 s - 6 c s^2 + 2 c^3 = 4

将(1)乘以3 s并加到(2):

(3)  -6 a c^2 s + 2 c^3 = 4

接下来,我们替换a = -S / C并使用S = 2scs^2 = 1 - c^2

(4)  12 c^3 (1 - c^2) / C + 2 c^3 = 4

乘以C = 2 c^2 - 1

(5)  c^3 (12 - 12 c^2 + 4 c^2 - 2) = 8 c^2 - 4

最后,

(6)   4 c^5 - 5 c^3 + 4 c^2 - 2 = 0

它有一对复杂的解,一个在余弦域之外的实解,另一个是给出x的四个主要解的两个解。

(7)   c_1/2 = 0.90520121, -0.57206084
(8)   x_1/2/3/4 = +/- 2 arccos(x_1/2)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM