Python Symphy无法解三角方程组

Python Symphy无法解三角方程组,python,sympy,Python,Sympy,我试图让Symphy解一个方程组,但它给了我一个错误,说: 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),

我试图让Symphy解一个方程组,但它给了我一个错误,说:

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)

Symphy可以用这个方程做得更好,但最终它相当于一些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可以使用第一个等式来消除:
y=x-tan(x)
,这对我们来说很容易看出,但SymPy有时会错过机会。让我们帮助它:

eq1 = eq[1].subs(y, x-tan(x))   #   3*sin(3*x/2)*tan(x)/2 + cos(3*x/2) - 2
同样地,
solve
solveset
(另一种Symphy解算器)放弃了方程,因为不同参数的三角函数混合在一起。我们中的一些人从上学时就记得三角函数可以表示为半参数正切的有理函数,所以让我们这样做:用
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\u 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=y-x
s=sint
c=cos t
s=sinx
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)乘以
3s
并加上(2):

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

(4)  12 c^3 (1 - c^2) / C + 2 c^3 = 4
C=2c^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)
(7)   c_1/2 = 0.90520121, -0.57206084
(8)   x_1/2/3/4 = +/- 2 arccos(x_1/2)