「SymPy」符号运算(3) (非)线性方程(组)求解、数列求和、连乘、求极限


SymPy

导言

在前两篇文章中,我们学习了SymPy的输入输出、基本符号、表达式、函数的定义和使用,以及表达式的化简、展开与合并。

传送链接:
「SymPy」符号运算(1) 简介/符号/变量/函数/表达式/等式/不等式/运算符
「SymPy」符号运算(2) 各种形式输出、表达式的化简合并与展开

本篇介绍SymPy方程求解,包括:线性/非线性方程求解、线性方程组求解和非线性方程组求解,求解结果分为符号解和数值解1。求解方程由两个主要函数:solve()solveset()

此外顺带学习一下求和式、连乘式、函数极限与数列极限的求解。

解方程(组)

有两个主要的函数都可以对方程进行求根:solve()solveset(),对一般的方程均能求解,如

from sympy.abc import x, y
from sympy import solve, solveset

solve(x**2 - y, x, dict=True)
# [{x: -sqrt(y)}, {x: sqrt(y)}]
solveset(x**2 - y, x)
# {-sqrt(y), sqrt(y)}

至于二者的区别,官方文档推荐我们根据以下需求进行选择

  1. solve()

    1. solve()函数的返回值可以相对容易地进行替换subs()而参与到其他的运算中
    2. 希望显式地获得满足方程的符号表达式
  2. solveset()

    1. 可以获得较为精确的数学解(通过设置mathematical sets
    2. 可以展现所有的解,甚至无穷多个解
    3. 可以自由地限制解的区间

solve函数

solve(f, *symbols, **flags) ,能够求解多项式、超越函数、分段函数、线性方程组等,举例:

x     = sympy.symbols('x')
expr1 = sympy.solve(x - 1, x)                   # 求满足方程 x - 1 = 0 的 x
print(expr1)
# [1]

x, y = sympy.symbols('x y')
expr2 = sympy.solve([2*x-y-3,3*x+y-7],[x,y])    # 线性方程组
print(expr2)
# {x: 2, y: 1}

也可以获得符号解,如 y ( x ) = x + 1 x − 1 y(x) = \dfrac{x + 1}{x - 1} y(x)=x1x+1,求 x ( y ) x(y) x(y)

x, y = symbols('x y')
expr = Eq((x + 1) / (x - 1), y)
print(solve(expr, x))                           # 直接将Eq投喂给solve函数
# [(y + 1)/(y - 1)]

当然*symbols参数也可以使用表达式或函数

solve(x + 2 + sqrt(3), x + 2)
# [-sqrt(3)]
solve(f(x) - x, f(x))
# [x]
solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
#  [x + f(x)]

# 使用可索引的符号A[i]
from sympy import Indexed, IndexedBase, Tuple, sqrt
A = IndexedBase('A')
eqs = Tuple(A[1] + A[2] - 3, A[1] - A[2] + 1)
solve(eqs, eqs.atoms(Indexed))
# {A[1]: 1, A[2]: 2}

*symbols参数也可以省略,此时SymPy自动判断哪些是待求解的符号

solve(x - 3)
# [3]
solve(x**2 - y**2)
# [{x: -y}, {x: y}]
solve(z**2*x**2 - z**2*y**2)
# [{x: -y}, {x: y}, {z: 0}]
solve(z**2*x - z**2*y**2)
# [{x: y**2}, {z: 0}]

如果不想得到完全的、显式的解,可以使用参数implicit=True,如求解 x + e x = 0 x+e^x=0 x+ex=0,可以得到解 x = − e x x = -e^x x=ex

solve(x + exp(x), x)
# [-LambertW(1)]
solve(x + exp(x), x, implicit=True)
# [-exp(x)]

求系数 a , b a, b a,b使得方程 ( a + b ) x − b + 2 = 0 (a+b)x - b + 2 = 0 (a+b)xb+2=0恒成立

solve((a + b)*x - b + 2, a, b)
# {a: -2, b: 2}

默认情况下,SymPy会在整个复数域进行求解,如果将解限制在实数域内,可以参考如下方法

from sympy import Symbol, solve
x = Symbol('x', real=True)
solve(x**4 - 256, x, dict=True)
[{x: -4}, {x: 4}]						# 如果不限制real=True,则输出{-4, 4, -4*I, 4*I}

带不等式条件的方程

solve([x < 3, x - 2])
# Eq(x, 2)
solve([x > 3, x - 2])
# False

部分可变参数**flags及缺省值:

  • dict=False:返回格式为方程的解的映射列表
  • set=False:返回格式为符号列表与解组成的元组
  • check=True:对解进行检查,会排除使分式的分母为零的解
  • simplify=True:是否对解进行化简,设为False可以缩短运行时间
  • force=False:是否不考虑符号的正负而进行强行化简

solveset函数

函数solveset(f, symbol=None, domain=Complexes) 可以在指定的域内求解等式或不等式,如果在实数域求解,可以用solveset_real,复数域可以用solveset_comples

x = Symbol('x')     # x = Symbol('x', real=True)时,求解结果一样(必须在solveset函数中指定求解域)
pprint(solveset(exp(x) - 1, x), use_unicode=False)
# {2*n*I*pi | n in Integers}

R = S.Reals
x = Symbol('x')
solveset(exp(x) - 1, x, R)
# {0}

solveset_real(exp(x) - 1, x)
# {0}

# 求解不等式
solveset(exp(x) > 1, x, R)
# Interval.open(0, oo)

求解单个方程时,solveset函数返回一个解集(solveset)、有限集(FiniteSet)、区间(Interval)或虚数集(ImageSet),当解不存在时,返回EmpySet空集,如果没在指定的符号限制之外找到了解,返回ConditionSet

i = Symbol('i', imaginary=True)
solveset(Eq(i**2 + i*sin(i), 1), i, domain=S.Reals)
# ConditionSet(_R, Eq(_R**2 + _R*sin(_R) - 1, 0), Reals)

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}

不等式只在实数域内求解,如果在复数域内给出不等式,将返回错误NotImplementedError

solveset(exp(x) > 1, x, R)
# Interval.open(0, oo)

求解反函数invert_real(f_x, y, x) (复数域可以用函数invert_complex(f_x, y, x, domain=Complexes)

invert_real(exp(x), y, x)
# (x, Intersection({log(y)}, Reals))

# When does exp(x) == 1?
invert_real(exp(x), 1, x)
# (x, {0})

在指定域内求解方程

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

线性方程组可以专门用函数linsolve(system, *symbols)求解

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)}

# Ax=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)}

非线性方程组可以用专门的函数nonlinsove求解(对于三角函数求根,最好用solve函数)

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⋅ⅈ)}

求和 ∑ \sum

sympy.summation(f, *symbols, **kwargs) ,用法:

                            b
                          ____
                          \   `
summation(f, (i, a, b)) =  )    f
                          /___,
                          i = a

直接上栗子:求 ∑ n = 1 100 3 n \sum_{n=1}^{100} 3n n=11003n

n     = sympy.Symbol('n', integer=True)
expr1 = sympy.summation(3 * n,(n,1,100))
print(expr1)
# 15150

∑ i = 1 n 2 i − 1 \sum_{i=1}^n 2i-1 i=1n2i1

from sympy import summation, oo, symbols, log
i, n, m = symbols('i n m', integer=True)
summation(2*i - 1, (i, 1, n))
# n**2

∑ i = 0 ∞ ( 1 2 ) i \sum_{i=0}^\infty \left(\frac{1}{2}\right)^i i=0(21)i

summation(1/2**i, (i, 0, oo))
# 2

∑ n = 0 m ∑ i = 0 n i , i = 0 , . . . , n , n = 0 , . . . , m \sum_{n=0}^m \sum_{i=0}^n i, \quad i=0, ..., n,\quad n=0, ..., m n=0mi=0ni,i=0,...,n,n=0,...,m

summation(i, (i, 0, n), (n, 0, m))
# m**3/6 + m**2/2 + m/3

连乘 ∏ \prod

连乘函数product(*args, **kwargs),用法:

                             b
                           _____
product(f(n), (i, a, b)) = |   | f(n)
                           |   |
                           i = a

直接上栗子, ∏ i = 1 k i \prod_{i=1}^k i i=1ki

from sympy import product, symbols
i, n, m, k = symbols('i n m k', integer=True)
    
product(i, (i, 1, k))
# factorial(k)

∏ i = 1 k m \prod_{i=1}^k m i=1km

product(m, (i, 1, k))
# m**k

∏ k = 1 n ∏ i = 1 k i \prod_{k=1}^n \prod_{i=1}^k i k=1ni=1ki

product(i, (i, 1, k), (k, 1, n))
# Product(factorial(k), (k, 1, n))

求函数极限

函数为limit(e, z, z0, dir='+') ,返回e(z)函数在z0处的极限。逼近方向dir+右逼近、-左逼近、+-左右逼近。栗子

from sympy import limit, sin, oo
from sympy.abc import x
limit(sin(x)/x, x, 0)
# 1
limit(1/x, x, 0) # default dir='+'
# oo
limit(1/x, x, 0, dir="-")
# -oo
limit(1/x, x, 0, dir='+-')
# zoo
limit(1/x, x, oo)
# 0

求数列极限

函数为limit_seq(expr, n=None, trials=5),返回表达式exprn趋于无穷大时的极限。trials为递归次数,如果返回了None可以尝试提高递归次数获得结果。栗子:

from sympy import limit_seq, Sum, binomial
from sympy.abc import n, k, m
limit_seq((5*n**3 + 3*n**2 + 4) / (3*n**3 + 4*n - 5), n)
# 5/3
limit_seq(binomial(2*n, n) / Sum(binomial(2*k, k), (k, 1, n)), n)        # binomial 二项式
# 3/4
limit_seq(Sum(k**2 * Sum(2**m/m, (m, 1, k)), (k, 1, n)) / (2**n*n), n)   # Sum (有限)求和
# 4

  1. Meurer A, Smith CP, Paprocki M, Čertík O, Kirpichev SB, Rocklin M, Kumar A, Ivanov S, Moore JK, Singh S, Rathnayake T, Vig S, Granger BE, Muller RP, Bonazzi F, Gupta H, Vats S, Johansson F, Pedregosa F, Curry MJ, Terrel AR, Roučka Š, Saboo A, Fernando I, Kulal S, Cimrman R, Scopatz A. (2017) SymPy: symbolic computing in Python. PeerJ Computer Science 3:e103 https://doi.org/10.7717/peerj-cs.103 ↩︎

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值