代数求解方程

使用 SymPy 代数(符号)求解方程。例如,求解 \(x^2 = y\) 得到 \(x \in \{-\sqrt{y},\sqrt{y}\}\)

需要考虑的替代方案

求解函数

有两种高级函数用于求解方程,solve()solveset()。以下是每个函数的示例:

solve()

>>> from sympy.abc import x, y
>>> from sympy import solve
>>> solve(x**2 - y, x, dict=True)
[{x: -sqrt(y)}, {x: sqrt(y)}]

solveset()

>>> from sympy import solveset
>>> from sympy.abc import x, y
>>> solveset(x**2 - y, x)
{-sqrt(y), sqrt(y)}

以下是关于何时使用的建议:

  • solve()

    • 您希望获得变量可能取的不同值的显式符号表示,这些值将满足方程。

    • 您希望将这些显式解值代入其他涉及同一变量的方程或表达式中,使用 subs()

  • solveset()

    • 您希望以数学上精确的方式表示解决方案,使用 数学集合

    • 你想要所有解决方案的表示,包括如果有无限多个的情况。

    • 您需要一个一致的输入接口。

    • 您希望将解决方案的域限制为任意集合。

    • 您不需要通过编程从解决方案集中提取解决方案:解决方案集不一定能通过编程进行查询。

指导

参见 Include the Variable to be Solved for in the Function Call确保从 solve() 的格式一致

代数求解方程

你可以用几种方法解一个方程。下面的例子展示了在适用的情况下使用 solve()solveset()。你可以选择最适合你方程的函数。

将你的方程式变为等于零的表达式

利用求解函数自动假设不在 Eq(方程)中的任何表达式等于零(0)这一事实。你可以将方程 \(x^2 = y\) 重新排列为 \(x^2 - y = 0\),并求解该表达式。如果你在交互式地求解一个已经等于零的表达式,或者你不介意将方程重新排列为 \(expression = 0\),这种方法会很方便。

>>> from sympy import solve, solveset
>>> from sympy.abc import x, y
>>> solve(x**2 - y, x, dict=True)
[{x: -sqrt(y)}, {x: sqrt(y)}]
>>> solveset(x**2 - y, x)
{-sqrt(y), sqrt(y)}

将你的方程放入 Eq 形式

将你的方程放入 Eq 形式,然后求解 Eq。如果你已经在方程形式中有一个方程,或者你认为它是一个等式,这种方法在交互式求解方程时很方便。它还有助于防止在两边相减时出现符号错误。

>>> from sympy import Eq, solve, solveset
>>> from sympy.abc import x, y
>>> eqn = Eq(x**2, y)
>>> eqn
Eq(x**2, y)
>>> solutions = solve(eqn, x, dict=True)
>>> print(solutions)
[{x: -sqrt(y)}, {x: sqrt(y)}]
>>> solutions_set = solveset(eqn, x)
>>> print(solutions_set)
{-sqrt(y), sqrt(y)}
>>> for solution_set in solutions_set:
...     print(solution_set)
sqrt(y)
-sqrt(y)

限制解的域

默认情况下,SymPy 会在复数域中返回解,这也包括纯实数和纯虚数。这里,前两个解是实数,后两个是虚数:

>>> from sympy import Symbol, solve, solveset
>>> x = Symbol('x')
>>> solve(x**4 - 256, x, dict=True)
[{x: -4}, {x: 4}, {x: -4*I}, {x: 4*I}]
>>> solveset(x**4 - 256, x)
{-4, 4, -4*I, 4*I}

要限制返回的解为实数,或其他定义域或范围,不同的求解函数使用不同的方法。

对于 solve(),对要解的符号 \(x\) 进行假设

>>> from sympy import Symbol, solve
>>> x = Symbol('x', real=True)
>>> solve(x**4 - 256, x, dict=True)
[{x: -4}, {x: 4}]

或者使用标准的Python技术来限制解决方案,例如列表推导式:

>>> from sympy import Or, Symbol, solve
>>> x = Symbol('x', real=True)
>>> expr = (x-4)*(x-3)*(x-2)*(x-1)
>>> solution = solve(expr, x)
>>> print(solution)
[1, 2, 3, 4]
>>> solution_outside_2_3 = [v for v in solution if (v.is_real and Or(v<2,v>3))]
>>> print(solution_outside_2_3)
[1, 4]

对于 solveset(),通过设置一个域来限制函数调用中的输出域

>>> from sympy import S, solveset
>>> from sympy.abc import x
>>> solveset(x**4 - 256, x, domain=S.Reals)
{-4, 4}

或者通过限制返回的解决方案为任意集合,包括一个区间:

>>> from sympy import Interval, pi, sin, solveset
>>> from sympy.abc import x
>>> solveset(sin(x), x, Interval(-pi, pi))
{0, -pi, pi}

如果你将解限制在一个没有解的域中,solveset() 将返回空集,EmptySet:

>>> from sympy import solveset, S
>>> from sympy.abc import x
>>> solveset(x**2 + 1, x, domain=S.Reals)
EmptySet

显式表示可能解的无穷集合

solveset() 可以表示可能解的无限集合,并用标准数学符号表达它们,例如对于 \(\sin(x) = 0\),解为 \(x = n * \pi\),其中 \(n\) 为任意整数值:

>>> from sympy import pprint, sin, solveset
>>> from sympy.abc import x
>>> solution = solveset(sin(x), x)
>>> pprint(solution)
{2*n*pi | n in Integers} U {2*n*pi + pi | n in Integers}

然而,solve() 只会返回有限数量的解:

>>> from sympy import sin, solve
>>> from sympy.calculus.util import periodicity
>>> from sympy.abc import x
>>> f = sin(x)
>>> solve(f, x)
[0, pi]
>>> periodicity(f, x)
2*pi

solve() 尝试返回足够多的解,以便通过加上方程periodicity()(此处为\(2\pi\))的整数倍,从返回的解中生成所有(无限多个)解。

使用解决方案结果

solve() 的替代解决方案代入表达式

你可以将 solve() 的解决方案代入一个表达式中。

一个常见的用例是找到函数 \(f\) 的临界点和临界值。在临界点处,Derivative 等于零(或未定义)。然后,您可以通过使用 subs() 将临界点代回函数来获得这些临界点处的函数值。您还可以通过将这些值代入二阶导数的表达式来判断临界点是极大值还是极小值:负值表示极大值,正值表示极小值。

>>> from sympy.abc import x
>>> from sympy import solve, diff
>>> f = x**3 + x**2 - x
>>> derivative = diff(f, x)
>>> critical_points = solve(derivative, x, dict=True)
>>> print(critical_points)
[{x: -1}, {x: 1/3}]
>>> point1, point2 = critical_points
>>> print(f.subs(point1))
1
>>> print(f.subs(point2))
-5/27
>>> curvature = diff(f, x, 2)
>>> print(curvature.subs(point1))
-4
>>> print(curvature.subs(point2))
4

solveset() 解集不一定能通过编程方式查询

如果 solveset() 返回一个有限集(类 FiniteSet),你可以遍历这些解:

>>> from sympy import solveset
>>> from sympy.abc import x, y
>>> solution_set = solveset(x**2 - y, x)
>>> print(solution_set)
{-sqrt(y), sqrt(y)}
>>> solution_list = list(solution_set)
>>> print(solution_list)
[sqrt(y), -sqrt(y)]

然而,对于更复杂的结果,可能无法列出解决方案:

>>> from sympy import S, solveset, symbols
>>> x, y = symbols('x, y')
>>> solution_set = solveset(x**2 - y, x, domain=S.Reals)
>>> print(solution_set)
Intersection({-sqrt(y), sqrt(y)}, Reals)
>>> list(solution_set)
Traceback (most recent call last):
    ...
TypeError: The computation had not completed because of the undecidable set
membership is found in every candidates.

在这种情况下,这是因为如果 \(y\) 是负数,它的平方根将是虚数而不是实数,因此超出了解集的声明域。通过声明 \(y\) 为实数且为正数,SymPy 可以确定其平方根是实数,从而解决解集与实数集之间的交集:

>>> from sympy import S, Symbol, solveset
>>> x = Symbol('x')
>>> y = Symbol('y', real=True, positive=True)
>>> solution_set = solveset(x**2 - y, x, domain=S.Reals)
>>> print(solution_set)
{-sqrt(y), sqrt(y)}
>>> list(solution_set)
[sqrt(y), -sqrt(y)]

或者,您可以使用 args 从解集提取集合,然后从包含符号解的集合创建一个列表:

>>> from sympy import S, solveset, symbols
>>> x, y = symbols('x, y')
>>> solution_set = solveset(x**2 - y, x, domain=S.Reals)
>>> print(solution_set)
Intersection({-sqrt(y), sqrt(y)}, Reals)
>>> solution_set_args = solution_set.args
>>> print(solution_set.args)
(Reals, {-sqrt(y), sqrt(y)})
>>> list(solution_set_args[1])
[sqrt(y), -sqrt(y)]

可以加速 solve() 的选项

参见 解决指南

并非所有方程都能被求解

无闭式解的方程

有些方程没有封闭形式的解,在这种情况下,SymPy 可能会返回一个空集或给出错误。例如,以下 超越方程 没有封闭形式的解:

>>> from sympy import cos, solve
>>> from sympy.abc import x
>>> solve(cos(x) - x, x, dict=True)
Traceback (most recent call last):
    ...
NotImplementedError: multiple generators [x, cos(x)]
No algorithms are implemented to solve equation -x + cos(x)

具有封闭形式解的方程,SymPy 无法求解

也可能存在一个代数解法来解决你的方程,而SymPy尚未实现适当的算法。如果发生这种情况,或者当存在数学解时SymPy返回一个空集或列表(表明SymPy存在错误),请在邮件列表上发布,或在SymPy的GitHub页面上提交问题。在问题解决之前,你可以数值求解你的方程

报告一个错误

如果你在使用解决函数时发现了一个错误,请在 SymPy 邮件列表 上发布问题。在问题解决之前,你可以使用 Alternatives to consider 中列出的其他方法。