跳至主要內容

Sympy 笔记

大约 12 分钟

Sympy 笔记

默认使用 import sympy as sy 导入 Sympy

参考教程 https://docs.sympy.org/latest/index.htmlopen in new window

表达式的基本操作

构建表达式

Sympy 中以变量符号对象为基础构建表达式

  • x = sy.symbol(a) 创建变量符号
    • a 字符串, 表示创建变量的符号, 可使用空格分隔创建多个变量
      • 使用 x:m 则可创建 x0xm-1m 个带有标号的变量
      • 使用 x:m:n 则可创建 x00xm-1n-1m * n 个带有标号的变量
      • 变量符号与接收变量符号对象的变量不一定要同名
      • 变量符号名称中没有空格即可, 因此可使用 \\theta_{1,2} 等 Latex 符号表示作为符号名称, 方便将表达式导出为 Laxte
    • 返回值为变量符号对象, 如果创建多个则为变量符号对象组成的元组
  • exp_res = sy.<数学函数>(exp)
    • exp 输入表达式, 变量符号或数值
    • 返回值为一个以输入表达式为变量的数学函数表达式, 如果传入数值将得到一个不含变量的表达式
    • 可用的数学函数有 sin, cos, exp, log, sqrt, 伽马函数 gamma, 阶乘 factorial

关于表达式还有如下说明

  • 表达式为 Python 对象, 可通过变量保存, 但表达式对象本身一般为不可变的, 只能通过表达式构造新的表达式
  • 变量符号实际为一种特殊的表达式, 通过表达式之间的数学运算即可构造新的表达式
  • 构造表达式时, Sympy 只会进行最低程度的化简, 如
    • 加减法中, 直接减去已有项, 如 x + y - x = y
    • 乘除法中, 直接消去公因式, 如 x * y / x = y
    • 尝试将含数值的表达式转换为最简形式, 如 sy.sqrt(8 * x) = 2 * sqrt(2) * sqrt(x)
    • 对于将表达式化简为特定形式见表达式化简部分

表达式操作

通过表达式对象的方法可对表达式进行操作

  • 变量代换 expr.subs(old, new) / expr.subs(dicts)
    • old 表达式 expr 中的变量符号对象或表达式 (传入表达式时将尝试从当前被修改表达式中匹配)
    • new 用于代换的表达式或数值
    • dicts 一个以变量符号对象为键, 代换表达式为值的字典, 通过该方法可一次代换多个参数
    • 返回值为一个新的表达式式, 即使所有变量都代换为数值, 得到的依然为表达式对象
  • 计算表达式的值 expr.evalf(n = 15, subs = None, maxn = 100, chop = False)
    • n 计算结果的精度
    • subs 一个以变量符号对象为键, 变量数值为值的字典, 表示计算表达式时各个变量的值, 如果表达式中没有变量可直接传入 None
    • maxn 计算表达式值时允许的最大精度
    • chop 传入 False 表示不忽略任何数值, 传入数值表示允许忽略比传入值小的量
  • 尝试将字符串转换为表达式 expr = sy.sympify(str)
    • str 表达式字符串
    • 返回值为转换的表达式, 如果要操作表达式中的变量应当使用 sy.symbols 创建对应名称的变量
  • 将表达式封装为 Python 函数 sy.lambdify(/, args, exprs, modules)
    • args 单个变量符号或变量符号列表, 表示函数接收参数对应的变量
    • exprs 用于封装的表达式对象, 当传入表达式列表时, 封装的函数将返回一个列表表示各个表达式的值
    • modules 封装中数学函数的实现模块, 使用字符串表示, 常用的有
      • numpy 封装中使用 Numpy 模块的数学函数, 此时可对函数传入 Numpy 数组
      • math 封装中使用 math 模块的数学函数

打印表达式

希望 Sympy 打印表达式前, 需要先调用函数 sy.init_printing() 进行初始化
以下为常用的打印表达式函数

  • 美化输出表达式 sy.pprint(expr)
    • expr 用于打印的表达式
    • 该函数将向终端打印美化的表达式输出
  • 获取 Latex 形式的表达式 sy.latex(expr, *)
    • expr 用于打印的表达式
    • 该函数将返回表达式的 Latex 形式的字符串
    • 通过传入参数可对样式进行设置, 以下为常用设置, 更多见官方文档open in new window
      • full_prec = False 是否将小数转为分数表示
      • diff_operator = 'd' 微分算子的字体, 默认为 dd, 使用参数 md 时表示 d\mathrm{d}
      • mat_symbol_style = 'plain' 矩阵变量的字体, 默认为一般字体 AA, 使用参数 bold 时表示 \mathbf{A}
      • ln_notation = False 对数函数表示, 默认为 log\log, 使用 True 时为 ln\ln
      • inv_trig_style = 'abbreviated' 反三角函数表示, 默认为缩写如 \asin\asin, 使用 full 时为全称如 arcsin\arcsin
      • parenthesize_super = True 当表达式被用于幂运算时, 加上括号
      • fold_func_brackets = False 允许时省略函数的括号

其他说明

  • 实用操作
    • expr.coeff(x, n) 提取系数
      • x 用于分析的变量符号
      • n 提取系数项的幂次
      • 返回结果为一个表达式, 即被提取的系数
  • 特殊符号的表示
    • 无穷 sy.oo
    • 虚数单位 sy.I

表达式化简

通过调用 Sympy 模块的函数, 可对表达式进行进一步化简

对于一般情况, 函数 sy.simplify(expr) 将尝试使输入表达式 expr 化简为最简的形式, 并进行一些必要的函数代换如 cos(x) ** 2 + sin(x) ** 2 = 1

对于其他的化简需求, 可使用以下化简函数

多项式化简

以下化简方法以多项式为核心进行, 将其他函数视为系数

  • sy.expand(expr) 展开为多项式之和
  • sy.factor(expr) 化简为多项式因式
  • sy.collect(expr, x, *, exact = False) 以指定变量 x 将表达式整理为关于该变量的各次幂与系数的多项式之和
    • expr 被整理的表达式
    • x 用于整理系数的变量, 表达式或表达式列表
    • exactTrue 时, 整理时将仅提取关于指定变量的因数, 而不包含其它次幂
    • 如选择变量 x 将表达式整理为类似 a * x ** 2 + b * x + c 的形式 (其中 x 可以是表达式或表达式列表)
  • sy.cancel(expr) 整理为多项式之和的分式
    • 对于含除法的多项式可使用该函数
    • 对于多项式因式的分式使用 sy.factor(expr) 即可
  • sy.apart(expr) 整理为多项式分式之和

其他化简函数

  • 三角函数化简
    以下化简方法以三角函数为核心进行 (同样适用于双曲三角函数)
    • sy.trigsimp(expr) 将表达式中所有类型的三角函数转化为单一类型
      该函数也倾向于将表达式整理到三角函数的变量内, 如 cosh2(x)+sinh2(x)=cosh(2x)\cosh^2(x) + \sinh^2(x)=\cosh(2x)
    • sy.expand_trig(expr) 将表达式中的三角函数整理为简单变量的形式如 sin(x+y)=sin(x)cos(y)+sin(y)cos(x)\sin(x + y) = \sin(x)\cos(y) + \sin(y)\cos(x)
  • 乘方表达式化简
    • sy.powsimp(expr) 将乘方表达式之间的乘法整理为单个乘方表达式
  • 对数表达式化简
    • sy.logcombine(expr) 将多个对数表达式的运算整理为单个对数表达式
    • sy.expand_log(expr) 将表达式中的对数整理为简单变量的形式
  • 其他化简函数参考官方文档open in new window
  • 如果希望从方程组中分离出特定变量的表达式, 应该考虑使用代数方程求解 sy.solve() 的方式实现

表达式运算

Sympy 中使用 sy.oo 表示无穷大

求导

  • 计算表达式求导结果 sy.diff(expr, *symbols)
    • expr 被求导的表达式
    • *symbols 按传入的符号顺序对表达式进行求导
      • 只传入变量符号对象时, 将按传入顺序分别求导
      • 可以传入元组 (sym, n), 表示对符号 sym 求导 n
  • 构造带求导算子的表达式 sy.Derivative(expr, *symbols)
    • 参数含义同 sy.diff(expr, *symbols)
    • 该函数仅构造表达式而不执行运算, 可调用表达式方法 expr.doit() 执行其中的运算

积分

  • 表达式积分结果 sy.integrate(expr, **args)
    • expr 被积分的表达式
    • args 按传入积分参数顺序对表达式进行多重积分
      • 只传入变量符号对象时, 将对该符号进行不定积分 (不包含常数 CC)
      • 可以传入元组 (sym, lower_limit, upper_limit), 表示对符号 sym 以上限 lower_limit 与下限 upper_limit 进行定积分
  • 构造带积分算子的表达式 sy.Integral(expr, **args)
    • 参数含义同 sy.integrate(expr, **args)
    • 该函数仅构造表达式而不执行运算, 可调用表达式方法 expr.doit() 执行其中的运算

其他运算

  • 表达式极限 sy.limit(e, z, z0, dir = '+')
    • e 被求极限的表达式
    • z 极限变量
    • z0 逼近的常量
    • + 求正方向邻域的极限 (如果求负方向邻域的极限则传入 -)
    • 类似有 sy.Limit(e, z, z0, dir = '+') 构造带极限算子的表达式
  • 泰勒级数展开 sy.series(expr, x, x0, n = 6, dir = '+')
    • expr 被泰勒展开的表达式
    • x 展开变量
    • x0 展开位置
    • n 展开阶数
    • dir 逼近方向
    • 返回值将带有该届无穷小表达式 O(x**n), 可对返回的表达式使用 expr.removeO() 去除
  • 傅里叶级数展开 见官方文档open in new window
  • 有限差分 见官方文档open in new window

方程求解

代数方程

  • 构造等式方程 sy.Eq(expr1, expr2)
    • expr1 等式左侧的表达式
    • expr2 等式右侧的表达式
    • 返回等式表达式
    • 注意, Sympy 中不能使用 === 构造等式方程, 只能使用函数 sy.Eq
      当非等式的表达式用于方程求解时, 将被视为等于 0 的方程
  • 以集合形式表示代数方程的解 sy.solveset(/, equation, variable, domain = sy.S.Complex)
    • equation 用于求解的等式, 可传入等式列表表示方程组
    • variable 方程中的待求变量, 可传放入变量对象元组, 表示多个待求变量
    • domain 变量所在的域, 常用有 sy.S.Real 表示实数域, sy.S.Complex 表示复数域
    • 该函数的返回值为集合, 如果有多个待求变量则返回向量的集合
    • 使用该函数可用于得到代数方程解的严格表达式, 特别是多个解的情况, 但无法表示重根
  • 以表达式形式表示代数方程的解 sy.solve(/, equation, variable, *, dict = False)
    • equation 用于求解的等式, 可传入等式列表表示方程组
    • variable 方程中的待求变量, 可传放入变量对象元组, 表示多个待求变量 (即使仅需要从方程组中求出一个量, 也应该写入所有应消去的变量, 以此表明剩余的变量为不必消去的常量)
    • dict 使用一个以待求变量为键, 解为值的字典表示解 (默认使用列表表示一组解, 列表的元素与传入的待求变量顺序对应)
    • 该函数的返回值为各个解组成的列表 (即使只有一个解或无解), 即使方程有无数解, 该函数也仅返回部分解
    • 该函数得到的解依然为表达式对象
  • 多项式方程求解 sy.roots(/, equation, variable)
    • equation 用于求解的多项式方程
    • variable 多项式方程变量
    • 该函数的返回值为以方程的根为键, 方程根的重数为值的字典
  • 求解方程的数值解 sy.nsolve(/, equation, x, x0 = None, *, dict = False)
    • equation 用于求解的等式, 可传入等式列表表示方程组
    • x 方程中的待求变量, 可传放入变量对象元组, 表示多个待求变量
    • x0 数值解的迭代起始值, 如果有多个起始值需要传入元组 (如果起始值为复数, 则将寻找复数解)
    • dict 是否以字典的形式返回解, 类似 sy.solve(dict = True)

常微分方程

  • 常微分方程中, 未知量为关于特定变量如 tt 的函数, 而不是一般的变量, 因此需要定义函数类型的变量对象
    • 首先创建函数表达式 y = sy.symbols(a, cls = sy.Function), 该函数即构建表达式函数, 但具有一个额外的参数
    • 由于没有绑定函数的自变量, 因此创建的函数表达式并不完整, 需要使用 y = y(t) 将变量 t 绑定为函数 y 的自变量 (允许绑定多个变量表示多元函数类型的变量对象)
    • 函数类型的变量对象的导数将保留微分算子, 因此两种求导方法没有区别
      表示微分方程时推荐使用 sy.diff()ypp = sy.diff(y, (t, 2))
  • 求解常微分方程的解析解 sy.dsolve(/, equation, function, *, ics = None)
    • equation 用于求解的常微分方程, 可传入等式元组表示方程组
    • function 方程中的待求函数, 可传放入函数类型变量对象元组, 表示多个待求函数
    • ics 方程组的边界条件
      • 默认没有给出初值条件, 则结果中将包含待定系数 Cx, 可先定义名称为 Cx 的变量符号再通过 expr.subs 带入具体值
      • 可传入一个字典, 字典的键为关于函数的已知条件, 值为已知条件的值, 例如 {f.diff(t).subs(0): 1} 体现边界条件 f(0)=1f'(0)=1
    • 函数的返回值为一个列表, 列表中的元素为各个待求函数的解 (等式形式), 其中函数在左侧, 函数表达式在右侧
      通过等式对象的成员 eq.rhs 可访问右侧的表达式
  • 求解常微分方程的数值解
    • 利用 sy.solve 构造 ddtX=F(X)\frac{\mathrm{d}}{\mathrm{d}t}\vec{X}=F(\vec{X}) 的常微分方程组
    • 利用 sy.lambdify 构造 Python 函数, 其中参数 exprs 为一个列表, 对应了各阶导数的表达式
    • 利用 Scipy 中的函数 scipy.integrate.solve_ivp 求出数值解

矩阵运算