求解器¶
备注
对于一个专注于解决常见类型方程的初学者友好指南,请参阅 解方程。
>>> 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)
。
代数解方程¶
求解代数方程的主要函数是 solveset
。solveset
的语法是 solveset(equation, variable=None, domain=S.Complexes)
,其中 equations
可以是 Eq
实例或假定为等于零的表达式。
请注意,还有一个名为 solve
的函数,也可以用来解方程。语法是 solve(equations, variables)
然而,建议使用 solveset
代替。
当解单个方程时,solveset
的输出是一个 FiniteSet
或一个 Interval
或 ImageSet
的解。
>>> 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
的示例。
当仅存在实数解时:
>>> 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)}
当只有复杂解决方案时:
>>> nonlinsolve([x**2 + 1, y**2 + 1], [x, y]) {(-ⅈ, -ⅈ), (-ⅈ, ⅈ), (ⅈ, -ⅈ), (ⅈ, ⅈ)}
当存在实数解和复数解时:
>>> 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)}
当系统是正维系统(有无限多个解)时:
>>> 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)}
备注
解决方案的顺序对应于给定符号的顺序。
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)
f
和 g
现在是未定义的函数。我们可以调用 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 解中的任意常数是形如 C1
、C2
、C3
等的符号。