【SymPy】(三)基本操作(四)打印

本文介绍了SymPy的基本操作,包括表达式的替换、字符串转换为表达式、数值计算及高效求值方法。此外还详细讲解了多种打印选项,如LaTeX、MathML等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【SymPy】(一)SymPy简介

【SymPy】(二)使用SymPy需要避开的坑

(三)基本操作

In [32]: from sympy import *
In [33]: x, y, z = symbols("x y z")

1 替换

对于数学表达式,最常见的一件事情是替换。替换是将表达式中某个对象替换为其他对象。它是使用subs方法完成的。例如

In [34]: expr = cos(x) + 1

In [35]: expr.subs(x, y)
Out[35]: cos(y) + 1

替换通常有以下两个作用:
1 在某一点上计算表达式的值。例如,已知表达式是cos(x)+1,如果我们想在x=0的点上计算它,那么我们得到cos(0)+1,也就是2。

In [36]: expr.subs(x, 0)
Out[36]: 2

2 用另一个子表达式替换表达式的子表达式。这么做主要有两个原因:
第一个原因是构建一个具有某种对称性的表达式 x x x x x^{x^{x^{x}}} xxxx,我们可以从x**y开始,用x**y替换y。然后我们得到x**(x**y)。然后我们用x**x替换这个新表达式中的y,我们将得到所需的表达式x**(x**(x**x))

In [38]: expr = x**y

In [39]: expr
Out[39]: x**y

In [40]: expr = expr.subs(y, x**y)

In [41]: expr
Out[41]: x**(x**y)

In [42]: expr = expr.subs(y, x**x)

In [43]: expr
Out[43]: x**(x**(x**x))

第二个原因是执行SymPy无法默认执行的简化。例如,有表达式sin(2x)+cos(2x),我们想用2 sin(x)cos(x)替换sin(2x)

虽然函数SymPy中的expand_trig可以实现这一点:

In [44]: expr = sin(2*x) + cos(2*x)

In [45]: expand_trig(expr)
Out[45]: 2*sin(x)*cos(x) + 2*cos(x)**2 - 1

但是这个函数还将同时扩展cos(2x),这可能是我们不需要的。

此时subs就派上用场了。

In [46]: expr.subs(sin(2*x), 2*sin(x)*cos(x))
Out[46]: 2*sin(x)*cos(x) + cos(2*x)

关于sub,有两点要注意。
首先,SymPy对象是不可变的,这意味着subs不会修改它。例如

In [50]: expr = cos(x)

In [51]: expr.subs(x, 0)
Out[51]: 1

In [52]: expr
Out[52]: cos(x)

In [53]: x
Out[53]: x

若要同时执行多个替换,可将(旧值、新值)配对的列表传递给sub

In [54]: expr = x**3 + 4*x*y - z

In [55]: expr.subs([(x, 2), (y, 4), (z, 0)])
Out[55]: 40

还可以与列表结合,一次完成大量相似的替换:

In [59]: expr = x**4 - 4*x**3 + 4*x**2 - 2*x + 3

In [60]: replacements = [(x**i, y**i) for i in range(5) if i % 2 == 0]

In [61]: replacements
Out[61]: [(1, 1), (x**2, y**2), (x**4, y**4)]

In [62]: expr.subs(replacements)
Out[62]: -4*x**3 - 2*x + y**4 + 4*y**2 + 3

2 将字符串转换为SymPy表达式

sympify函数(注意不要与simplify混淆)可用于将字符串转换为SymPy表达式。
例如:

In [64]: str_expr = "x**2 + 3*x - 1/2"

In [65]: expr = sympify(str_expr)

In [66]: expr
Out[66]: x**2 + 3*x - 1/2

In [67]: expr.subs(x, 2)
Out[67]: 19/2

警告:sympify使用了eval。输入必须初始化。
反例:

expr = sympify(“x**2 + 3*x - 1/2)

3 evalf

要将数值表达式求值为浮点数,则使用evalf

In [69]: expr = sqrt(8)

In [70]: expr.evalf()
Out[70]: 2.82842712474619

可以指定小数点位数,比如 π \pi π小数点后100位:

In [72]: pi.evalf(100)
Out[72]: 3.1415926535897932384626433832795028841971693993751058209749445923078164
06286208998628034825342117068

要对符号的表达式在某一个点上进行数值计算,我们可以使用subs后跟evalf,但是使用subs flag将替换传递给evalf更有效,数值上更稳定,它需要一个符号字典:点对( point pairs)。

In [73]: expr = cos(2*x)

In [74]: expr.evalf(subs={x: 2.4})
Out[74]: 0.0874989834394464

有时,在计算表达式之后,仍存在小于所需精度的舍入误差。用户可以通过将chopflag设置为True来自行删除这些数字。

In [77]: one = cos(1)**2 + sin(1)**2

In [78]: (one - 1).evalf()
Out[78]: -0.e-124

In [79]: (one - 1).evalf(chop=True)
Out[79]: 0

3 lambdify

如果你想做简单的求值,使用subsevalf就够了,但是如果你想在许多点上求值表达式,有更有效的方法。
例如,如果你想在一千个点上计算一个表达式,使用SymPy会很慢,特别是在你只关心机器精度的时候。此时,你应该使用NumPy和SciPy这样的库。

将SymPy表达式转换为可进行数值计算的表达式的最简单方法是使用lambdify函数。lambdify的作用类似于lambda函数,只是表达不同,例如

In [85]: import numpy

In [86]: a = numpy.arange(10)

In [87]: expr = sin(x)

In [89]: f = lambdify(x, expr, "numpy")

In [90]: f(a)
Out[90]: 
array([ 0.        ,  0.84147098,  0.90929743,  0.14112001, -0.7568025 ,
       -0.95892427, -0.2794155 ,  0.6569866 ,  0.98935825,  0.41211849])

注意:lambdify使用eval。输入必须初始化。

你也可以使用NumPy以外的其他库。例如math

In [93]: f = lambdify(x, expr, "math")

In [94]: f(0.1)
Out[94]: 0.09983341664682815

要将lambdify用于自定义的数值函数,可传递一个字典:数值函数对(numerical_function pairs)。例如

In [99]: def mysin(x):
    ...:     """
    ...:     My sine. Note that this is only accurate for small x.
    ...:     """
    ...:     return x
    ...: 

In [100]: f = lambdify(x, expr, {"sin":mysin})

In [101]: f(0.1)
Out[101]: 0.1

(四)打印

从前面的文章我们知道,SymPy可以使用Unicode字符打印出好看的输出( Unicode pretty printer)。本文将对SymPy中最常见的打印选项的简短介绍。

1 打印机

SymPy有几种打印机。最常见的是
• str
• srepr
• ASCII pretty printer
• Unicode pretty printer
• LaTeX
• MathML
• Dot

2 设置 Pretty Printing

如果你只想要最好的Pretty Printing,可使用 init_printing()函数。这将自动启用环境中可用的最佳打印机。

如果你打算在交互式计算器类型会话( interactive calculator-type session)中工作, init_session()函数将自动导入SymPy中的所有内容,创建一些公共符号,设置绘图,并运行init_printing()

In [104]: from sympy import init_session

In [105]: init_session()
IPython console for SymPy 1.1.1 (Python 3.6.6-64-bit) (ground types: python)

These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> init_printing()

之后可能会有以下的几种情况:

  • 在IPython QTConsole中,如果安装了 LaTeX \LaTeX LATEX,它将使用 LaTeX \LaTeX LATEX的打印机。

如果未安装 LaTeX \LaTeX LATEX,但安装了Matplotlib,则它将使用Matplotlib渲染引擎。如果未安装Matplotlib,它将使用 Unicode pretty printer。

  • 在 IPython notebook中,它将使用MathJax渲染 LaTeX \LaTeX LATEX

• 在IPython控制台会话或常规Python会话中,如果终端支持Unicode,它将使用Unicode pretty printer。

  • 在不支持Unicode的终端中,使用ASCII pretty printer。

若要显式不使用 LaTeX \LaTeX LATEX,则将use_latex=False传递给init_printing()init_session().。若要显式不使用Unicode,则传递 use_unicode=False

3 打印函数

除了自动打印之外,你还可以通过调用适当的函数显式使用任何一种打印机。

3.1 str

要获取表达式的字符串形式,则使用str(expr)

In [1]: from sympy import *

In [2]: x, y, z = symbols('x y z')

In [3]: str(Integral(sqrt(1/x), x))
Out[3]: 'Integral(sqrt(1/x), x)'

In [4]: print(Integral(sqrt(1/x), x))
Integral(sqrt(1/x), x)
3.2 srepr

表达式的srepr形式旨在显示表达式的精确形式。

In [5]: srepr(Integral(sqrt(1/x), x))
Out[5]: "Integral(Pow(Pow(Symbol('x'), Integer(-1)), Rational(1, 2)), Tuple(Symbol('x')))"

3.3 ASCII Pretty Printer

pprint()使用了 ASCII Pretty Printer。如果终端不支持Unicode,则默认使用 ASCII Pretty Printer。否则,必须通过use_unicode=False.

In [6]: pprint(Integral(sqrt(1/x), x), use_unicode=False)
  /
 |
 |     ___
 |    / 1
 |   /  -  dx
 | \/   x
 |
/

pprint()将输出打印到屏幕上。如果需要字符串形式,可使用pretty()

In [7]: pretty(Integral(sqrt(1/x), x), use_unicode=False)
Out[7]: '  /          \n |           \n |     ___   \n |    / 1    \n |   /  -  d
x\n | \\/   x    \n |           \n/            '

In [8]: print(pretty(Integral(sqrt(1/x), x), use_unicode=False))
  /
 |
 |     ___
 |    / 1
 |   /  -  dx
 | \/   x
 |
/
3.4 Unicode Pretty Printer

Unicode Pretty Printer也可以从pprint()pretty()访问。如果终端支持Unicode,则会自动使用。如果pprint()无法检测到终端支持的unicode,则可以传递use_unicode=True以强制其使用unicode。

In [9]: pprint(Integral(sqrt(1/x), x), use_unicode=True)
   ...: 
⌠
⎮     ___
⎮    ╱ 1
⎮   ╱  ─  dx
⎮ ╲╱   x
⌡
3.5 LaTeX \LaTeX LATEX

要获得表达式的 LaTeX \LaTeX LATEX代码,则使用 latex()

In [10]: print(latex(Integral(sqrt(1/x), x)))
\int \sqrt{\frac{1}{x}}\, dx
3.6 MathML

使用print_mathml()

In [11]: from sympy.printing.mathml import print_mathml

In [12]: print_mathml(Integral(sqrt(1/x), x))
<apply>
        <int/>
        <bvar>
                <ci>x</ci>
        </bvar>
        <apply>
                <root/>
                <apply>
                        <power/>
                        <ci>x</ci>
                        <cn>-1</cn>
                </apply>
        </apply>
</apply>

3.7 Dot

SymPy中的dotprint()函数同类型打印.dot以点格式打印输出,可以用Graphviz呈现。

In [13]: from sympy.printing.dot import dotprint

In [14]: from sympy.abc import x

In [15]: print(dotprint(x+2))
digraph{

# Graph style
"ordering"="out"
"rankdir"="TD"

#########
# Nodes #
#########

"Add(Integer(2), Symbol(x))_()" ["color"="black", "label"="Add", "shape"="ellipse
"];
"Integer(2)_(0,)" ["color"="black", "label"="2", "shape"="ellipse"];
"Symbol(x)_(1,)" ["color"="black", "label"="x", "shape"="ellipse"];

#########
# Edges #
#########

"Add(Integer(2), Symbol(x))_()" -> "Integer(2)_(0,)";
"Add(Integer(2), Symbol(x))_()" -> "Symbol(x)_(1,)";
}

未完待续:

【SymPy】(五)简化

【SymPy】(六)微积分

【SymPy】(七)方程求解

【SymPy】(八)矩阵

【SymPy】(九)高级表达式操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二进制人工智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值