[英]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
,由于不同参数的三角函数的这种混合,所以solve
和solveset
(替代的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/2
, a = yx
, s = sin t
, c = cos t
, S = sin x
和C = 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 = 2sc
和s^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.