求解器

备注

对于一个专注于解决常见类型方程的初学者友好指南,请参阅 解方程

>>> from sympy import *
>>> x, y, z = symbols('x y z')
>>> init_printing(use_unicode=True)

关于方程的说明

回顾本教程的 注意事项 部分,SymPy 中的符号方程不是由 === 表示的,而是由 Eq 表示的。

>>> Eq(x, y)
x = y

然而,有一个更简单的方法。在 SymPy 中,任何不在 Eq 中的表达式都会被求解函数自动假设为等于 0。由于 \(a = b\) 当且仅当 \(a - b = 0\),这意味着你可以直接使用 x - y,而不是 x == y。例如

>>> solveset(Eq(x**2, 1), x)
{-1, 1}
>>> solveset(Eq(x**2 - 1, 0), x)
{-1, 1}
>>> solveset(x**2 - 1, x)
{-1, 1}

如果你要解的方程已经等于0,这特别有用。你不需要输入 solveset(Eq(expr, 0), x),只需使用 solveset(expr, x)

代数解方程

求解代数方程的主要函数是 solvesetsolveset 的语法是 solveset(equation, variable=None, domain=S.Complexes),其中 equations 可以是 Eq 实例或假定为等于零的表达式。

请注意,还有一个名为 solve 的函数,也可以用来解方程。语法是 solve(equations, variables) 然而,建议使用 solveset 代替。

当解单个方程时,solveset 的输出是一个 FiniteSet 或一个 IntervalImageSet 的解。

>>> solveset(x**2 - x, x)
{0, 1}
>>> solveset(x - x, x, domain=S.Reals)

>>> solveset(sin(x) - 1, x, domain=S.Reals)
⎧        π │      ⎫
⎨2⋅n⋅π + ─ │ n ∊ ℤ⎬
⎩        2 │      ⎭

如果没有解决方案,则返回 EmptySet,如果无法找到解决方案,则返回 ConditionSet

>>> solveset(exp(x), x)     # No solution exists

>>> solveset(cos(x) - x, x)  # Not able to find solution
{x │ x ∊ ℂ ∧ (-x + cos(x) = 0)}

solveset 模块中,线性方程组通过 linsolve 求解。未来我们将能够直接从 solveset 使用 linsolve。以下是 linsolve 语法的示例。

  • 方程列表形式:

    >>> linsolve([x + y + z - 1, x + y + 2*z - 3 ], (x, y, z))
    {(-y - 1, y, 2)}
    
  • 增广矩阵形式:

    >>> linsolve(Matrix(([1, 1, 1, 1], [1, 1, 2, 3])), (x, y, z))
    {(-y - 1, y, 2)}
    
  • A*x = b 形式

    >>> M = Matrix(((1, 1, 1, 1), (1, 1, 2, 3)))
    >>> system = A, b = M[:, :-1], M[:, -1]
    >>> linsolve(system, x, y, z)
    {(-y - 1, y, 2)}
    

备注

解决方案的顺序对应于给定符号的顺序。

solveset 模块中,非线性方程组使用 nonlinsolve 来求解。以下是 nonlinsolve 的示例。

  1. 当仅存在实数解时:

    >>> a, b, c, d = symbols('a, b, c, d', real=True)
    >>> nonlinsolve([a**2 + a, a - b], [a, b])
    {(-1, -1), (0, 0)}
    >>> nonlinsolve([x*y - 1, x - 2], x, y)
    {(2, 1/2)}
    
  2. 当只有复杂解决方案时:

    >>> nonlinsolve([x**2 + 1, y**2 + 1], [x, y])
    {(-ⅈ, -ⅈ), (-ⅈ, ⅈ), (ⅈ, -ⅈ), (ⅈ, ⅈ)}
    
  3. 当存在实数解和复数解时:

    >>> from sympy import sqrt
    >>> system = [x**2 - 2*y**2 -2, x*y - 2]
    >>> vars = [x, y]
    >>> nonlinsolve(system, vars)
    {(-2, -1), (2, 1), (-√2⋅ⅈ, √2⋅ⅈ), (√2⋅ⅈ, -√2⋅ⅈ)}
    
    >>> system = [exp(x) - sin(y), 1/y - 3]
    >>> nonlinsolve(system, vars)
    {({2⋅n⋅ⅈ⋅π + log(sin(1/3)) │ n ∊ ℤ}, 1/3)}
    
  4. 当系统是正维系统(有无限多个解)时:

    >>> nonlinsolve([x*y, x*y - x], [x, y])
    {(0, y)}
    
    >>> system = [a**2 + a*c, a - b]
    >>> nonlinsolve(system, [a, b])
    {(0, 0), (-c, -c)}
    

备注

  1. 解决方案的顺序对应于给定符号的顺序。

2. Currently nonlinsolve doesn’t return solution in form of LambertW (if there is solution present in the form of LambertW).

solve 可以用于此类情况:

>>> solve([x**2 - y**2/exp(x)], [x, y], dict=True)
⎡⎧         ____⎫  ⎧        ____⎫⎤
⎢⎨        ╱  x ⎬  ⎨       ╱  x ⎬⎥
⎣⎩y: -x⋅╲╱  ℯ  ⎭, ⎩y: x⋅╲╱  ℯ  ⎭⎦
>>> solve(x**2 - y**2/exp(x), x, dict=True)
⎡⎧      ⎛-y ⎞⎫  ⎧      ⎛y⎞⎫⎤
⎢⎨x: 2⋅W⎜───⎟⎬, ⎨x: 2⋅W⎜─⎟⎬⎥
⎣⎩      ⎝ 2 ⎠⎭  ⎩      ⎝2⎠⎭⎦

3. Currently nonlinsolve is not properly capable of solving the system of equations having trigonometric functions.

solve 可以用于此类情况(但并不提供所有解决方案):

>>> solve([sin(x + y), cos(x - y)], [x, y])
⎡⎛-3⋅π   3⋅π⎞  ⎛-π   π⎞  ⎛π  3⋅π⎞  ⎛3⋅π  π⎞⎤
⎢⎜─────, ───⎟, ⎜───, ─⎟, ⎜─, ───⎟, ⎜───, ─⎟⎥
⎣⎝  4     4 ⎠  ⎝ 4   4⎠  ⎝4   4 ⎠  ⎝ 4   4⎠⎦

solveset 每个解只报告一次。要获取包括重数的多项式解,请使用 roots

>>> solveset(x**3 - 6*x**2 + 9*x, x)
{0, 3}
>>> roots(x**3 - 6*x**2 + 9*x, x)
{0: 1, 3: 2}

roots 的输出 {0: 1, 3: 2} 意味着 0 是一个重数为 1 的根,而 3 是一个重数为 2 的根。

备注

目前 solveset 无法解决以下类型的方程:

  • 可通过 LambertW 求解的方程(超越方程求解器)。

solve 可以用于此类情况:

>>> solve(x*exp(x) - 1, x )
[W(1)]

解微分方程

要解微分方程,请使用 dsolve。首先,通过向 symbols 函数传递 cls=Function 来创建一个未定义的函数。

>>> f, g = symbols('f g', cls=Function)

fg 现在是未定义的函数。我们可以调用 f(x),它将表示一个未知函数。

>>> f(x)
f(x)

f(x) 的导数是未计算的。

>>> f(x).diff(x)
d
──(f(x))
dx

(有关导数的更多信息,请参阅 导数 部分)。

要表示微分方程 \(f''(x) - 2f'(x) + f(x) = \sin(x)\),我们因此会使用

>>> diffeq = Eq(f(x).diff(x, x) - 2*f(x).diff(x) + f(x), sin(x))
>>> diffeq
                      2
         d           d
f(x) - 2⋅──(f(x)) + ───(f(x)) = sin(x)
         dx           2
                    dx

要解这个常微分方程(ODE),将它和要解的函数传递给 dsolve

>>> dsolve(diffeq, f(x))
                    x   cos(x)
f(x) = (C₁ + C₂⋅x)⋅ℯ  + ──────
                          2

dsolve 返回一个 Eq 的实例。这是因为,一般来说,微分方程的解不能显式地求解函数。

>>> dsolve(f(x).diff(x)*(1 - sin(f(x))) - 1, f(x))
x - f(x) - cos(f(x)) = C₁

dsolve 解中的任意常数是形如 C1C2C3 等的符号。