SymPy-1-13-中文文档-二十二-

104 阅读1小时+

SymPy 1.13 中文文档(二十二)

原文:docs.sympy.org/latest/index.html

离散

原文链接:docs.sympy.org/latest/modules/discrete.html

在 SymPy 的discrete模块中实现了计算有限序列的离散变换和卷积的方法。

该模块包含对离散序列操作的函数。

Transforms - fft, ifft, ntt, intt, fwht, ifwht,

mobius_transform, inverse_mobius_transform

卷积 - convolution, convolution_fft, convolution_ntt,

convolution_fwht, convolution_subset, covering_product, intersecting_product

由于离散变换可用于降低离散卷积的计算复杂度,convolutions模块利用transforms模块进行高效计算(适用于长输入序列)。

变换

该部分列出了实现离散序列基本变换的方法。

快速傅立叶变换

sympy.discrete.transforms.fft(seq, dps=None)

在复数域中执行离散傅立叶变换(DFT)。

由于基数-2 FFT需要样本点数为 2 的幂,序列会自动向右填充零。

仅对短序列使用默认参数,因为表达式复杂度会随序列大小增加而增加。

参数:

seq:可迭代对象

应用DFT的序列。

dps:整数

指定精度的小数位数。

示例

>>> from sympy import fft, ifft 
>>> fft([1, 2, 3, 4])
[10, -2 - 2*I, -2, -2 + 2*I]
>>> ifft(_)
[1, 2, 3, 4] 
>>> ifft([1, 2, 3, 4])
[5/2, -1/2 + I/2, -1/2, -1/2 - I/2]
>>> fft(_)
[1, 2, 3, 4] 
>>> ifft([1, 7, 3, 4], dps=15)
[3.75, -0.5 - 0.75*I, -1.75, -0.5 + 0.75*I]
>>> fft(_)
[1.0, 7.0, 3.0, 4.0] 

参考

[R178]

en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm

[R179]

mathworld.wolfram.com/FastFourierTransform.html

sympy.discrete.transforms.ifft(seq, dps=None)

在复数域中执行离散傅立叶变换(DFT)。

由于基数-2 FFT需要样本点数为 2 的幂,序列会自动向右填充零。

仅对短序列使用默认参数,因为表达式复杂度会随序列大小增加而增加。

参数:

seq:可迭代对象

应用DFT的序列。

dps:整数

指定精度的小数位数。

示例

>>> from sympy import fft, ifft 
>>> fft([1, 2, 3, 4])
[10, -2 - 2*I, -2, -2 + 2*I]
>>> ifft(_)
[1, 2, 3, 4] 
>>> ifft([1, 2, 3, 4])
[5/2, -1/2 + I/2, -1/2, -1/2 - I/2]
>>> fft(_)
[1, 2, 3, 4] 
>>> ifft([1, 7, 3, 4], dps=15)
[3.75, -0.5 - 0.75*I, -1.75, -0.5 + 0.75*I]
>>> fft(_)
[1.0, 7.0, 3.0, 4.0] 

参考

[R180]

en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm

[R181]

mathworld.wolfram.com/FastFourierTransform.html

数论变换

sympy.discrete.transforms.ntt(seq, prime)

执行数论变换(NTT),专门针对素数(p)的商环(Z/pZ)上的离散傅立叶变换(DFT),而不是复数(C)。

由于基数-2 NTT需要样本点数为 2 的幂,序列会自动向右填充零。

参数:

seq:可迭代对象

应用DFT的序列。

prime : 整数

用于在序列上执行 NTT 的形式为((m 2^k + 1))的素数模数。

示例

>>> from sympy import ntt, intt
>>> ntt([1, 2, 3, 4], prime=3*2**8 + 1)
[10, 643, 767, 122]
>>> intt(_, 3*2**8 + 1)
[1, 2, 3, 4]
>>> intt([1, 2, 3, 4], prime=3*2**8 + 1)
[387, 415, 384, 353]
>>> ntt(_, prime=3*2**8 + 1)
[1, 2, 3, 4] 

参考文献

[R182]

www.apfloat.org/ntt.html

[R183]

mathworld.wolfram.com/NumberTheoreticTransform.html

[R184]

[en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29](en.wikipedia.org/wiki/Discre…

sympy.discrete.transforms.intt(seq, prime)

执行 Number Theoretic Transform(NTT),它专门用于素数(p)而不是复数(C)的环(Z/pZ)上的离散傅里叶变换(DFT)。

序列会自动在右侧填充零,因为基数-2 NTT要求样本点数为 2 的幂。

参数:

seq : iterable

应用 DFT 的序列。

prime : 整数

用于在序列上执行 NTT 的形式为((m 2^k + 1))的素数模数。

示例

>>> from sympy import ntt, intt
>>> ntt([1, 2, 3, 4], prime=3*2**8 + 1)
[10, 643, 767, 122]
>>> intt(_, 3*2**8 + 1)
[1, 2, 3, 4]
>>> intt([1, 2, 3, 4], prime=3*2**8 + 1)
[387, 415, 384, 353]
>>> ntt(_, prime=3*2**8 + 1)
[1, 2, 3, 4] 

参考文献

[R185]

www.apfloat.org/ntt.html

[R186]

mathworld.wolfram.com/NumberTheoreticTransform.html

[R187]

[en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29](en.wikipedia.org/wiki/Discre…

快速 Walsh-Hadamard 变换

sympy.discrete.transforms.fwht(seq)

执行 Walsh Hadamard Transform(WHT),并使用 Hadamard 排序序列。

序列会自动在右侧填充零,因为基数-2 FWHT要求样本点数为 2 的幂。

参数:

seq : iterable

应用 WHT 的序列。

示例

>>> from sympy import fwht, ifwht
>>> fwht([4, 2, 2, 0, 0, 2, -2, 0])
[8, 0, 8, 0, 8, 8, 0, 0]
>>> ifwht(_)
[4, 2, 2, 0, 0, 2, -2, 0] 
>>> ifwht([19, -1, 11, -9, -7, 13, -15, 5])
[2, 0, 4, 0, 3, 10, 0, 0]
>>> fwht(_)
[19, -1, 11, -9, -7, 13, -15, 5] 

参考文献

[R188]

en.wikipedia.org/wiki/Hadamard_transform

[R189]

en.wikipedia.org/wiki/Fast_Walsh%E2%80%93Hadamard_transform

sympy.discrete.transforms.ifwht(seq)

执行 Walsh Hadamard Transform(WHT),并使用 Hadamard 排序序列。

序列会自动在右侧填充零,因为基数-2 FWHT要求样本点数为 2 的幂。

参数:

seq : iterable

应用 WHT 的序列。

示例

>>> from sympy import fwht, ifwht
>>> fwht([4, 2, 2, 0, 0, 2, -2, 0])
[8, 0, 8, 0, 8, 8, 0, 0]
>>> ifwht(_)
[4, 2, 2, 0, 0, 2, -2, 0] 
>>> ifwht([19, -1, 11, -9, -7, 13, -15, 5])
[2, 0, 4, 0, 3, 10, 0, 0]
>>> fwht(_)
[19, -1, 11, -9, -7, 13, -15, 5] 

参考文献

[R190]

en.wikipedia.org/wiki/Hadamard_transform

[R191]

en.wikipedia.org/wiki/Fast_Walsh%E2%80%93Hadamard_transform

Möbius 变换

sympy.discrete.transforms.mobius_transform(seq, subset=True)

对子集格上的索引执行 Möbius 变换。

每个参数的索引,被视为位串,对应于有限集的子集。

序列会被自动用零填充到右边,因为基于位掩码(索引)的子集/超集的定义要求序列的大小必须是 2 的幂。

参数:

seq:可迭代对象

要应用 Mobius 变换的序列。

subset:布尔类型

通过枚举给定集合的子集或超集来确定是否应用 Mobius 变换。

示例

>>> from sympy import symbols
>>> from sympy import mobius_transform, inverse_mobius_transform
>>> x, y, z = symbols('x y z') 
>>> mobius_transform([x, y, z])
[x, x + y, x + z, x + y + z]
>>> inverse_mobius_transform(_)
[x, y, z, 0] 
>>> mobius_transform([x, y, z], subset=False)
[x + y + z, y, z, 0]
>>> inverse_mobius_transform(_, subset=False)
[x, y, z, 0] 
>>> mobius_transform([1, 2, 3, 4])
[1, 3, 4, 10]
>>> inverse_mobius_transform(_)
[1, 2, 3, 4]
>>> mobius_transform([1, 2, 3, 4], subset=False)
[10, 6, 7, 4]
>>> inverse_mobius_transform(_, subset=False)
[1, 2, 3, 4] 

参考文献

[R192]

en.wikipedia.org/wiki/M%C3%B6bius_inversion_formula

[R193]

people.csail.mit.edu/rrw/presentations/subset-conv.pdf

[R194]

arxiv.org/pdf/1211.0189.pdf

sympy.discrete.transforms.inverse_mobius_transform(seq, subset=True)

对序列的子集格上的指数进行 Mobius 变换。

每个参数的索引被视为位串,对应于有限集合的子集。

序列会被自动用零填充到右边,因为基于位掩码(索引)的子集/超集的定义要求序列的大小必须是 2 的幂。

参数:

seq:可迭代对象

要应用 Mobius 变换的序列。

subset:布尔类型

通过枚举给定集合的子集或超集来确定是否应用 Mobius 变换。

示例

>>> from sympy import symbols
>>> from sympy import mobius_transform, inverse_mobius_transform
>>> x, y, z = symbols('x y z') 
>>> mobius_transform([x, y, z])
[x, x + y, x + z, x + y + z]
>>> inverse_mobius_transform(_)
[x, y, z, 0] 
>>> mobius_transform([x, y, z], subset=False)
[x + y + z, y, z, 0]
>>> inverse_mobius_transform(_, subset=False)
[x, y, z, 0] 
>>> mobius_transform([1, 2, 3, 4])
[1, 3, 4, 10]
>>> inverse_mobius_transform(_)
[1, 2, 3, 4]
>>> mobius_transform([1, 2, 3, 4], subset=False)
[10, 6, 7, 4]
>>> inverse_mobius_transform(_, subset=False)
[1, 2, 3, 4] 

参考文献

[R195]

en.wikipedia.org/wiki/M%C3%B6bius_inversion_formula

[R196]

people.csail.mit.edu/rrw/presentations/subset-conv.pdf

[R197]

arxiv.org/pdf/1211.0189.pdf ## 卷积

此部分列出了用于离散序列基本卷积的方法。

卷积

这是一种计算离散序列卷积的通用方法,内部调用 convolution_fft, convolution_ntt, convolution_fwhtconvolution_subset 中的一种方法。

sympy.discrete.convolutions.convolution(a, b, cycle=0, dps=None, prime=None, dyadic=None, subset=None)

使用提示来执行所需卷积类型的卷积。

dps, prime, dyadic, subset 参数中,应明确指定一种以识别卷积类型,可选择地指定参数 cycle

对于默认参数,使用 FFT 执行线性卷积。

参数:

a, b:可迭代对象

要进行卷积的序列。

cycle:整数

指定进行循环卷积的长度。

dps:整数

指定在序列上执行 FFT 时的精度所需的小数位数。

prime:整数

用于在序列上执行 NTT 的形式为 ((m 2^k + 1)) 的素数模数。

dyadic:布尔类型

将卷积类型标识为二元(按位异或)卷积,使用 FWHT 执行。

subset:布尔类型

将卷积类型标识为子集卷积。

示例

>>> from sympy import convolution, symbols, S, I
>>> u, v, w, x, y, z = symbols('u v w x y z') 
>>> convolution([1 + 2*I, 4 + 3*I], [S(5)/4, 6], dps=3)
[1.25 + 2.5*I, 11.0 + 15.8*I, 24.0 + 18.0*I]
>>> convolution([1, 2, 3], [4, 5, 6], cycle=3)
[31, 31, 28] 
>>> convolution([111, 777], [888, 444], prime=19*2**10 + 1)
[1283, 19351, 14219]
>>> convolution([111, 777], [888, 444], prime=19*2**10 + 1, cycle=2)
[15502, 19351] 
>>> convolution([u, v], [x, y, z], dyadic=True)
[u*x + v*y, u*y + v*x, u*z, v*z]
>>> convolution([u, v], [x, y, z], dyadic=True, cycle=2)
[u*x + u*z + v*y, u*y + v*x + v*z] 
>>> convolution([u, v, w], [x, y, z], subset=True)
[u*x, u*y + v*x, u*z + w*x, v*z + w*y]
>>> convolution([u, v, w], [x, y, z], subset=True, cycle=3)
[u*x + v*z + w*y, u*y + v*x, u*z + w*x] 

使用快速傅立叶变换进行卷积的序列。

sympy.discrete.convolutions.convolution_fft(a, b, dps=None)

使用快速傅立叶变换执行线性卷积。

参数:

a, b:可迭代对象

进行卷积的序列。

dps:整数

指定精度的十进制数字位数。

示例

>>> from sympy import S, I
>>> from sympy.discrete.convolutions import convolution_fft 
>>> convolution_fft([2, 3], [4, 5])
[8, 22, 15]
>>> convolution_fft([2, 5], [6, 7, 3])
[12, 44, 41, 15]
>>> convolution_fft([1 + 2*I, 4 + 3*I], [S(5)/4, 6])
[5/4 + 5*I/2, 11 + 63*I/4, 24 + 18*I] 

参考文献

[R198]

en.wikipedia.org/wiki/Convolution_theorem

[R199]

[en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29](en.wikipedia.org/wiki/Discre…

使用数论变换执行卷积

sympy.discrete.convolutions.convolution_ntt(a, b, prime)

使用数论变换执行线性卷积。

参数:

a, b:可迭代对象

进行卷积的序列。

prime:整数

用于在序列上执行 NTT 的形式为((m 2^k + 1))的素数模数。

示例

>>> from sympy.discrete.convolutions import convolution_ntt
>>> convolution_ntt([2, 3], [4, 5], prime=19*2**10 + 1)
[8, 22, 15]
>>> convolution_ntt([2, 5], [6, 7, 3], prime=19*2**10 + 1)
[12, 44, 41, 15]
>>> convolution_ntt([333, 555], [222, 666], prime=19*2**10 + 1)
[15555, 14219, 19404] 

参考文献

[R200]

en.wikipedia.org/wiki/Convolution_theorem

[R201]

[en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29](en.wikipedia.org/wiki/Discre…

使用快速沃尔什-哈达玛变换执行子集卷积。

sympy.discrete.convolutions.convolution_fwht(a, b)

使用快速沃尔什-哈达玛变换进行二进制(按位异或)卷积。

该卷积会自动用零填充到右侧,因为基于位掩码的 Radix-2 FWHT要求采样点数为 2 的幂。

参数:

a, b:可迭代对象

进行卷积的序列。

示例

>>> from sympy import symbols, S, I
>>> from sympy.discrete.convolutions import convolution_fwht 
>>> u, v, x, y = symbols('u v x y')
>>> convolution_fwht([u, v], [x, y])
[u*x + v*y, u*y + v*x] 
>>> convolution_fwht([2, 3], [4, 5])
[23, 22]
>>> convolution_fwht([2, 5 + 4*I, 7], [6*I, 7, 3 + 4*I])
[56 + 68*I, -10 + 30*I, 6 + 50*I, 48 + 32*I] 
>>> convolution_fwht([S(33)/7, S(55)/6, S(7)/4], [S(2)/3, 5])
[2057/42, 1870/63, 7/6, 35/4] 

参考文献

[R202]

www.radioeng.cz/fulltexts/2002/02_03_40_42.pdf

[R203]

en.wikipedia.org/wiki/Hadamard_transform

子集卷积

sympy.discrete.convolutions.convolution_subset(a, b)

对给定序列执行子集卷积。

每个参数的索引,视为位字符串,对应于有限集合的子集。

该序列会自动用零填充到右侧,因为基于位掩码(索引)的子集定义要求序列大小为 2 的幂。

参数:

a, b:可迭代对象

进行卷积的序列。

示例

>>> from sympy import symbols, S
>>> from sympy.discrete.convolutions import convolution_subset
>>> u, v, x, y, z = symbols('u v x y z') 
>>> convolution_subset([u, v], [x, y])
[u*x, u*y + v*x]
>>> convolution_subset([u, v, x], [y, z])
[u*y, u*z + v*y, x*y, x*z] 
>>> convolution_subset([1, S(2)/3], [3, 4])
[3, 6]
>>> convolution_subset([1, 3, S(5)/7], [7])
[7, 21, 5, 0] 

参考文献

[R204]

people.csail.mit.edu/rrw/presentations/subset-conv.pdf

覆盖乘积

sympy.discrete.convolutions.covering_product(a, b)

返回给定序列的覆盖乘积。

每个参数的索引,视为位字符串,对应于有限集合的子集。

给定序列的覆盖乘积是一个序列,其中包含给定序列的元素按相应索引的按位或分组后的乘积之和。

该序列会自动用零填充到右侧,因为基于位掩码(索引)的子集定义要求序列大小为 2 的幂。

参数:

a, b:可迭代对象

进行覆盖乘积的序列。

示例

>>> from sympy import symbols, S, I, covering_product
>>> u, v, x, y, z = symbols('u v x y z') 
>>> covering_product([u, v], [x, y])
[u*x, u*y + v*x + v*y]
>>> covering_product([u, v, x], [y, z])
[u*y, u*z + v*y + v*z, x*y, x*z] 
>>> covering_product([1, S(2)/3], [3, 4 + 5*I])
[3, 26/3 + 25*I/3]
>>> covering_product([1, 3, S(5)/7], [7, 8])
[7, 53, 5, 40/7] 

参考文献

[R205]

people.csail.mit.edu/rrw/presentations/subset-conv.pdf

交集积

sympy.discrete.convolutions.intersecting_product(a, b)

返回给定序列的交集积。

每个参数的指数,被视为位字符串,对应于有限集的子集。

给定序列的交集积是包含给定序列元素按对应索引的位与(bitwise-AND)计算的乘积和的序列。

由于基于位掩码(索引)的子集定义要求序列的大小是 2 的幂次方,因此序列会自动在右侧填充零。

参数:

a, b : 可迭代对象

所需获取交集积的序列。

示例

>>> from sympy import symbols, S, I, intersecting_product
>>> u, v, x, y, z = symbols('u v x y z') 
>>> intersecting_product([u, v], [x, y])
[u*x + u*y + v*x, v*y]
>>> intersecting_product([u, v, x], [y, z])
[u*y + u*z + v*y + x*y + x*z, v*z, 0, 0] 
>>> intersecting_product([1, S(2)/3], [3, 4 + 5*I])
[9 + 5*I, 8/3 + 10*I/3]
>>> intersecting_product([1, 3, S(5)/7], [7, 8])
[327/7, 24, 0, 0] 

参考文献

[R206]

people.csail.mit.edu/rrw/presentations/subset-conv.pdf

数值评估

原文:docs.sympy.org/latest/modules/evalf.html

基础

精确的 SymPy 表达式可以使用 .evalf() 方法或 N() 函数转换为浮点数近似值(小数)。N(expr, <args>) 等效于 sympify(expr).evalf(<args>)

>>> from sympy import *
>>> N(sqrt(2)*pi)
4.44288293815837
>>> (sqrt(2)*pi).evalf()
4.44288293815837 

默认情况下,数值评估的精度为 15 位小数。您可以选择将所需的精度(应为正整数)作为参数传递给 evalfN

>>> N(sqrt(2)*pi, 5)
4.4429
>>> N(sqrt(2)*pi, 50)
4.4428829381583662470158809900606936986146216893757 

支持复数:

>>> N(1/(pi + I), 20)
0.28902548222223624241 - 0.091999668350375232456*I 

如果表达式包含符号或由于其他原因无法进行数值评估,则调用 .evalf()N() 将返回原始表达式,或者在某些情况下返回部分评估的表达式。例如,当表达式是展开形式的多项式时,将评估系数:

>>> x = Symbol('x')
>>> (pi*x**2 + x/3).evalf()
3.14159265358979*x**2 + 0.333333333333333*x 

您还可以使用标准 Python 函数 float()complex() 将 SymPy 表达式转换为常规 Python 数字:

>>> float(pi)  
3.141592653589793
>>> complex(pi+E*I)  
(3.141592653589793+2.718281828459045j) 

如果使用这些函数,未能将表达式评估为显式数字(例如,如果表达式包含符号),则会引发异常。

本质上不存在上限精度限制。例如,以下命令计算了π/e 的前 100,000 位小数:

>>> N(pi/E, 100000) 
... 

这显示了π的第 999,951 至 1,000,000 位小数:

>>> str(N(pi, 10**6))[-50:] 
'95678796130331164628399634646042209010610577945815' 

高精度计算可能会很慢。建议(但完全可选)安装 gmpy(github.com/aleaxit/gmpy),这将显著加快上述计算等的速度。

浮点数

SymPy 中的浮点数是 Float 类的实例。可以将 Float 作为第二个参数创建自定义精度:

>>> Float(0.1)
0.100000000000000
>>> Float(0.1, 10)
0.1000000000
>>> Float(0.125, 30)
0.125000000000000000000000000000
>>> Float(0.1, 30)
0.100000000000000005551115123126 

正如最后一个示例所示,某些 Python 浮点数仅精确到约 15 位小数输入,而其他(例如分母为 2 的幂的浮点数,如 0.125 = 1/8)则是精确的。要从高精度小数创建 Float,最好传递字符串、Rationalevalf Rational

>>> Float('0.1', 30)
0.100000000000000000000000000000
>>> Float(Rational(1, 10), 30)
0.100000000000000000000000000000
>>> Rational(1, 10).evalf(30)
0.100000000000000000000000000000 

数的精度决定了 1)在与该数进行算术运算时使用的精度,以及 2)打印该数时显示的位数。当两个不同精度的数一起进行算术运算时,结果将使用较高的精度。0.1 +/- 0.001 和 3.1415 +/- 0.0001 的乘积的不确定性约为 0.003,但显示了 5 位有效数字。

>>> Float(0.1, 3)*Float(3.1415, 5)
0.31417 

因此,显示的精度不应用作错误传播或重要性算术的模型;相反,该方案用于确保数值算法的稳定性。

Nevalf 可用于更改现有浮点数的精度:

>>> N(3.5)
3.50000000000000
>>> N(3.5, 5)
3.5000
>>> N(3.5, 30)
3.50000000000000000000000000000 

精度和错误处理

当输入到 Nevalf 的是复杂表达式时,数值误差传播成为一个问题。例如,考虑第 100 个斐波那契数和卓越但不精确的近似 (\varphi^{100} / \sqrt{5}),其中 (\varphi) 是黄金比例。使用普通浮点算术,将这些数字相减会错误地导致完全的取消:

>>> a, b = GoldenRatio**1000/sqrt(5), fibonacci(1000)
>>> float(a)
4.34665576869e+208
>>> float(b)
4.34665576869e+208
>>> float(a) - float(b)
0.0 

Nevalf 会跟踪错误并自动增加内部使用的精度,以获得正确的结果:

>>> N(fibonacci(100) - GoldenRatio**100/sqrt(5))
-5.64613129282185e-22 

不幸的是,数值评估无法区分一个恰好为零的表达式和一个仅仅非常小的表达式。因此,默认情况下工作精度被限制在大约 100 位数字。如果我们尝试使用第 1000 个斐波那契数,会发生以下情况:

>>> N(fibonacci(1000) - (GoldenRatio)**1000/sqrt(5))
0.e+85 

返回数字的位数不足表明 N 未能达到完全的精确度。结果表明表达式的大小为 10⁸⁴ 以下,但这并不是一个特别好的答案。要强制使用更高的工作精度,可以使用 maxn 关键字参数:

>>> N(fibonacci(1000) - (GoldenRatio)**1000/sqrt(5), maxn=500)
-4.60123853010113e-210 

通常情况下,maxn 可以设置得非常高(数千位数字),但请注意,这可能在极端情况下导致显著的减速。或者,可以将 strict=True 选项设置为强制引发异常,而不是在请求的精度不足时静默返回值:

>>> N(fibonacci(1000) - (GoldenRatio)**1000/sqrt(5), strict=True)
Traceback (most recent call last):
...
PrecisionExhausted: Failed to distinguish the expression:

-sqrt(5)*GoldenRatio**1000/5 + 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875

from zero. Try simplifying the input, using chop=True, or providing a higher maxn for evalf 

如果我们添加一个项,使得斐波那契逼近变得精确(Binet 公式的完整形式),我们得到一个恰好为零的表达式,但 N 不知道这一点:

>>> f = fibonacci(100) - (GoldenRatio**100 - (GoldenRatio-1)**100)/sqrt(5)
>>> N(f)
0.e-104
>>> N(f, maxn=1000)
0.e-1336 

在已知会发生这种取消的情况下,chop 选项非常有用。这基本上会将数字的实部或虚部中非常小的数替换为精确的零:

>>> N(f, chop=True)
0
>>> N(3 + I*f, chop=True)
3.00000000000000 

在希望去除无意义数字的情况下,重新评估或使用 round 方法非常有用:

>>> Float('.1', '')*Float('.12345', '')
0.012297
>>> ans = _
>>> N(ans, 1)
0.01
>>> ans.round(2)
0.01 

如果处理的数值表达式不包含浮点数,可以以任意精度进行评估。要将结果舍入到给定小数的相对值,round 方法非常有用:

>>> v = 10*pi + cos(1)
>>> N(v)
31.9562288417661
>>> v.round(3)
31.956 

总和与积分

总和(特别是无穷级数)和积分可以像常规闭合形式表达式一样使用,并支持任意精度评估:

>>> var('n x')
(n, x)
>>> Sum(1/n**n, (n, 1, oo)).evalf()
1.29128599706266
>>> Integral(x**(-x), (x, 0, 1)).evalf()
1.29128599706266
>>> Sum(1/n**n, (n, 1, oo)).evalf(50)
1.2912859970626635404072825905956005414986193682745
>>> Integral(x**(-x), (x, 0, 1)).evalf(50)
1.2912859970626635404072825905956005414986193682745
>>> (Integral(exp(-x**2), (x, -oo, oo)) ** 2).evalf(30)
3.14159265358979323846264338328 

默认情况下,使用双曲正弦积分算法来评估积分。对于平滑的被积函数(甚至是具有端点奇异性的积分),此算法非常高效和稳健,但可能在高度振荡或中间间断的积分中遇到困难。在许多情况下,evalf / N 将正确估计误差。对于以下积分,结果是准确的,但只精确到四位数:

>>> f = abs(sin(x))
>>> Integral(abs(sin(x)), (x, 0, 4)).evalf()
2.346 

最好将这个积分拆分成两个部分:

>>> (Integral(f, (x, 0, pi)) + Integral(f, (x, pi, 4))).evalf()
2.34635637913639 

类似的例子是以下振荡积分:

>>> Integral(sin(x)/x**2, (x, 1, oo)).evalf(maxn=20)
0.5 

可以通过告知 evalfN 使用振荡积分算法来更有效地处理它:

>>> Integral(sin(x)/x**2, (x, 1, oo)).evalf(quad='osc')
0.504067061906928
>>> Integral(sin(x)/x**2, (x, 1, oo)).evalf(20, quad='osc')
0.50406706190692837199 

振荡积分需要包含形如 cos(ax+b) 或 sin(ax+b) 因子的被积函数。请注意,许多其他振荡积分可以通过变量变换转换为此形式:

>>> init_printing(use_unicode=False)
>>> intgrl = Integral(sin(1/x), (x, 0, 1)).transform(x, 1/x)
>>> intgrl
 oo
 /
 |
 |  sin(x)
 |  ------ dx
 |     2
 |    x
 |
/
1
>>> N(intgrl, quad='osc')
0.504067061906928 

如果无穷级数收敛速度足够快,直接求和。否则,使用外推方法(通常是欧拉-麦克劳林公式但也包括理查森外推)加速收敛。这允许对缓慢收敛级数进行高精度评估:

>>> var('k')
k
>>> Sum(1/k**2, (k, 1, oo)).evalf()
1.64493406684823
>>> zeta(2).evalf()
1.64493406684823
>>> Sum(1/k-log(1+1/k), (k, 1, oo)).evalf()
0.577215664901533
>>> Sum(1/k-log(1+1/k), (k, 1, oo)).evalf(50)
0.57721566490153286060651209008240243104215933593992
>>> EulerGamma.evalf(50)
0.57721566490153286060651209008240243104215933593992 

欧拉-麦克劳林公式还用于有限级数,允许快速近似而不需评估所有项:

>>> Sum(1/k, (k, 10000000, 20000000)).evalf()
0.693147255559946 

请注意,evalf 做出了不总是最优的一些假设。为了对数值求和进行精细调整,手动使用 Sum.euler_maclaurin 方法可能是值得的。

为了有理超几何级数(其中项是多项式、幂、阶乘、二项式系数等的乘积)采用了特殊优化。N/evalf 类型的级数可以非常快速地高精度求和。例如,这个拉马努金公式可以用简单的命令在几分之一秒内求和到 10,000 位数:

>>> f = factorial
>>> n = Symbol('n', integer=True)
>>> R = 9801/sqrt(8)/Sum(f(4*n)*(1103+26390*n)/f(n)**4/396**(4*n),
...                         (n, 0, oo))
>>> N(R, 10000) 
3.141592653589793238462643383279502884197169399375105820974944592307816406286208
99862803482534211706798214808651328230664709384460955058223172535940812848111745
02841027019385211055596446229489549303819644288109756659334461284756482337867831
... 

数值简化

函数 nsimplify 尝试找到一个数值上等于给定输入的公式。此功能可用于猜测精确浮点输入的确切公式,或者猜测复杂符号输入的简化公式。nsimplify 使用的算法能够识别简单分数、简单代数表达式、给定常数的线性组合以及任何前述内容的某些基本函数变换。

可选地,nsimplify 可以传入常数列表(例如 pi)和最小数值容差。以下是一些基本示例:

>>> nsimplify(0.1)
1/10
>>> nsimplify(6.28, [pi], tolerance=0.01)
2*pi
>>> nsimplify(pi, tolerance=0.01)
22/7
>>> nsimplify(pi, tolerance=0.001)
355
---
113
>>> nsimplify(0.33333, tolerance=1e-4)
1/3
>>> nsimplify(2.0**(1/3.), tolerance=0.001)
635
---
504
>>> nsimplify(2.0**(1/3.), tolerance=0.001, full=True)
3 ___
\/ 2 

这里是几个更高级的示例:

>>> nsimplify(Float('0.130198866629986772369127970337',30), [pi, E])
 1
----------
5*pi
---- + 2*e
 7
>>> nsimplify(cos(atan('1/3')))
 ____
3*\/ 10
--------
 10
>>> nsimplify(4/(1+sqrt(5)), [GoldenRatio])
-2 + 2*GoldenRatio
>>> nsimplify(2 + exp(2*atan('1/4')*I))
49   8*I
-- + ---
17    17
>>> nsimplify((1/(exp(3*pi*I/5)+1)))
 ___________
 /   ___
1        /  \/ 5    1
- - I*  /   ----- + -
2     \/      10    4
>>> nsimplify(I**I, [pi])
 -pi
 ----
 2
e
>>> n = Symbol('n')
>>> nsimplify(Sum(1/n**2, (n, 1, oo)), [pi])
 2
pi
---
 6
>>> nsimplify(gamma('1/4')*gamma('3/4'), [pi])
 ___
\/ 2 *pi 

数值计算

原文链接:docs.sympy.org/latest/modules/numeric-computation.html

像 SymPy 这样的符号计算代数系统有助于构建和操作数学表达式。但是,当需要对数值数据进行评估时,符号系统的性能通常较差。

幸运的是,SymPy 提供了许多易于使用的钩子,可以连接到其他数值系统,允许您在 SymPy 中创建数学表达式,然后将其传送到您选择的数值系统。本页记录了许多可用选项,包括math库、流行的数组计算包numpy、在 Fortran 或 C 中生成代码以及使用数组编译器Aesara

Subs/evalf

Subs 是最慢但最简单的选项。它以 SymPy 的速度运行。.subs(...).evalf()方法可以用数值值替换符号值,然后在 SymPy 中评估结果。

>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x
>>> expr.evalf(subs={x: 3.14})
0.000507214304613640 

这种方法速度较慢。仅在性能不是问题时,才应在生产中使用此方法。你可以预期.subs耗时数十微秒。在原型设计阶段或者只需查看值时,这可能很有用。

Lambdify

lambdify函数将 SymPy 表达式转换为 Python 函数,利用各种数值库。其用法如下:

>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x
>>> f = lambdify(x, expr)
>>> f(3.14)
0.000507214304614 

在这里,lambdify 创建一个计算f(x) = sin(x)/x的函数。默认情况下,lambdify 依赖于math标准库中的实现。这种数值评估大约需要数百纳秒,比.subs方法快大约两个数量级。这是 SymPy 和原始 Python 之间的速度差异。

Lambdify 可以利用多种数值后端。默认情况下使用math库。但它也支持mpmath和最显著的是numpy。使用numpy库可以让生成的函数访问由编译的 C 代码支持的强大的矢量化 ufuncs。

>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x
>>> f = lambdify(x, expr, "numpy") 
>>> import numpy
>>> data = numpy.linspace(1, 10, 10000)
>>> f(data)
[ 0.84147098  0.84119981  0.84092844 ... -0.05426074 -0.05433146
 -0.05440211] 

如果你有基于数组的数据,这可能会显著加快速度,每个元素大约在 10 纳秒左右。不幸的是,NumPy 会产生一些启动时间,并引入几微秒的额外开销。

CuPy 是一个与 NumPy 兼容的数组库,主要运行在 CUDA 上,但也越来越多地支持其他 GPU 制造商。在许多情况下,它可以作为 numpy 的即插即用替代品。

>>> f = lambdify(x, expr, "cupy")
>>> import cupy as cp
>>> data = cp.linspace(1, 10, 10000)
>>> y = f(data) # perform the computation
>>> cp.asnumpy(y) # explicitly copy from GPU to CPU / numpy array
[ 0.84147098  0.84119981  0.84092844 ... -0.05426074 -0.05433146
 -0.05440211] 

JAX 是 CuPy 的类似替代方案,通过即时编译到 XLA 提供 GPU 和 TPU 加速。在某些情况下,它也可以作为 numpy 的即插即用替代品。

>>> f = lambdify(x, expr, "jax")
>>> import jax.numpy as jnp
>>> data = jnp.linspace(1, 10, 10000)
>>> y = f(data) # perform the computation
>>> numpy.asarray(y) # explicitly copy to CPU / numpy array
array([ 0.84147096,  0.8411998 ,  0.84092844, ..., -0.05426079,
 -0.05433151, -0.05440211], dtype=float32) 

uFuncify

内联代码(autowrap)模块包含一些能够帮助进行高效计算的方法。

  • autowrap 方法用于编译由 codegen 模块生成的代码,并将二进制包装供 Python 使用。

  • binary_function 方法自动化了将 SymPy 表达式自动包装并附加到Function对象的步骤。

  • ufuncify 生成一个二元函数,支持在 numpy 数组上进行广播,使用不同的后端比subs/evalflambdify更快。

所有上述内容的 API 参考在这里列出:sympy.utilities.autowrap()

Aesara

SymPy 与Aesara有着紧密的连接,是一个数学数组编译器。SymPy 表达式可以轻松转换为 Aesara 图,然后使用 Aesara 编译器链进行编译。

>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x 
>>> from sympy.printing.aesaracode import aesara_function
>>> f = aesara_function([x], [expr]) 

如果希望进行数组广播或者类型处理,Aesara 需要额外的信息。

>>> f = aesara_function([x], [expr], dims={x: 1}, dtypes={x: 'float64'}) 

Aesara 比 SymPy 的 C/Fortran 代码打印机有一个更复杂的代码生成系统。除其他外,它处理常见的子表达式,并编译到 GPU 上。Aesara 还支持 SymPy 的 Matrix 和 Matrix Expression 对象。

所以我应该使用哪一个?

这里的选项按从最慢和最少依赖到最快和最多依赖的顺序列出。例如,如果安装了 Aesara,则通常是最佳选择。如果没有安装 Aesara 但安装了f2py,则应使用ufuncify。如果您一直使用 numpy 模块使用 lambdify,并且有 GPU,那么 CuPy 和 JAX 可以提供显著的加速效果而几乎没有额外工作。

工具速度特性依赖项
subs/evalf50us简单None
lambdify1us标量函数math
lambdify-numpy10ns向量函数numpy
ufuncify10ns复杂向量表达式f2py, Cython
lambdify-cupy10nsGPU 上的向量函数cupy
lambdify-jax10nsCPU、GPU 和 TPU 上的向量函数jax
Aesara10ns多输出,CSE,GPUAesara

项重写

原文链接:docs.sympy.org/latest/modules/rewriting.html

术语重写是一种非常一般化的功能类,用于将一种类型的表达式转换为不同种类的表达式。例如,展开、组合和转换表达式适用于术语重写,同时还可以包括简化例程。目前 SymPy 具有多个函数和基本内置方法,用于执行各种类型的重写。

展开

最简单的重写规则是将表达式展开成稀疏形式。展开有几种类型,包括复值表达式的展开,乘积和幂的算术展开,以及将函数展开为更一般的函数。以下列出了所有当前可用的展开规则。

对涉及乘积和幂的算术表达式的展开:

>>> from sympy import *
>>> x, y, z = symbols('x,y,z')
>>> ((x + y)*(x - y)).expand(basic=True)
x**2 - y**2
>>> ((x + y + z)**2).expand(basic=True)
x**2 + 2*x*y + 2*x*z + y**2 + 2*y*z + z**2 

默认情况下,在 expand() 中进行算术展开,因此可以省略关键字 basic。但是,如果使用下面描述的规则,可以设置 basic=False 来避免这种类型的展开。这样可以完全控制表达式的处理方式。

另一种展开规则是将复值表达式展开并将其放入正常形式。可以使用 complex 关键字来实现这一点。请注意,它将始终执行算术展开以获得所需的正常形式:

>>> (x + I*y).expand(complex=True)
re(x) + I*re(y) + I*im(x) - im(y) 
>>> sin(x + I*y).expand(complex=True)
sin(re(x) - im(y))*cosh(re(y) + im(x)) + I*cos(re(x) - im(y))*sinh(re(y) + im(x)) 

还要注意,可以使用 as_real_imag() 方法来获得相同的行为。但是,它会返回一个包含实部在第一位和虚部在其他位置的元组。可以通过使用 collect 函数进行两步处理来完成这个过程:

>>> (x + I*y).as_real_imag()
(re(x) - im(y), re(y) + im(x)) 
>>> collect((x + I*y).expand(complex=True), I, evaluate=False)
{1: re(x) - im(y), I: re(y) + im(x)} 

还可以按不同种类的表达式展开表达式。这是一种非常一般化的展开类型,通常会使用 rewrite() 来进行特定类型的重写:

>>> GoldenRatio.expand(func=True)
1/2 + sqrt(5)/2 

公共子表达式检测和收集

在评估大型表达式之前,通常有助于识别公共子表达式,收集它们并一次性评估它们。这在 cse 函数中实现。例如:

>>> from sympy import cse, sqrt, sin, pprint
>>> from sympy.abc import x

>>> pprint(cse(sqrt(sin(x))), use_unicode=True)
⎛    ⎡  ________⎤⎞
⎝[], ⎣╲╱ sin(x) ⎦⎠

>>> pprint(cse(sqrt(sin(x)+5)*sqrt(sin(x)+4)), use_unicode=True)
⎛                ⎡  ________   ________⎤⎞
⎝[(x₀, sin(x))], ⎣╲╱ x₀ + 4 ⋅╲╱ x₀ + 5 ⎦⎠

>>> pprint(cse(sqrt(sin(x+1) + 5 + cos(y))*sqrt(sin(x+1) + 4 + cos(y))),
...     use_unicode=True)
⎛                             ⎡  ________   ________⎤⎞
⎝[(x₀, sin(x + 1) + cos(y))], ⎣╲╱ x₀ + 4 ⋅╲╱ x₀ + 5 ⎦⎠

>>> pprint(cse((x-y)*(z-y) + sqrt((x-y)*(z-y))), use_unicode=True)
⎛                          ⎡  ____     ⎤⎞
⎝[(x₀, (x - y)⋅(-y + z))], ⎣╲╱ x₀  + x₀⎦⎠ 

可以在 optimizations 可选参数中传递公共子表达式消除之前和之后要执行的优化。可以通过传递 optimizations='basic' 应用一组预定义的基本优化:

>>> pprint(cse((x-y)*(z-y) + sqrt((x-y)*(z-y)), optimizations='basic'),
...     use_unicode=True)
⎛                          ⎡  ____     ⎤⎞
⎝[(x₀, -(x - y)⋅(y - z))], ⎣╲╱ x₀  + x₀⎦⎠ 

然而,对于大型表达式来说,这些优化可能会非常缓慢。此外,如果速度是一个问题,可以传递选项 order='none'。然后,术语的顺序将取决于哈希算法的实现,但速度将得到极大的改善。

更多信息:

sympy.simplify.cse_main.cse(exprs, symbols=None, optimizations=None, postprocess=None, order='canonical', ignore=(), list=True)

对表达式进行公共子表达式消除。

参数:

exprs:SymPy 表达式列表,或单个 SymPy 表达式

待减少的表达式。

symbols:产生唯一符号的无限迭代器

用于标记被提取的共同子表达式的符号。 numbered_symbols 生成器非常有用。默认情况下是形式为 "x0"、"x1" 等的符号流。这必须是一个无限迭代器。

optimizations:(可调用,可调用)对列表

外部优化函数的(预处理器,后处理器)对。可选地,可以传递 'basic' 以获得一组预定义的基本优化。这些“basic”优化在旧实现中默认使用,但在较大的表达式上可能非常慢。现在,默认情况下不进行预处理或后处理优化。

postprocess:接受 cse 的两个返回值的函数和

返回从 cse 中的期望输出形式,例如如果您希望替换反转,则函数可能是以下 lambda:lambda r, e: return reversed(r), e

order:字符串,'none' 或 'canonical'

处理 Mul 和 Add 参数的顺序。如果设置为 'canonical',参数将按照规范顺序排列。如果设置为 'none',排序将更快但依赖于表达式哈希,因此是机器相关和可变的。对于速度是关键问题的大型表达式,请使用 order='none'。

ignore:符号的可迭代集合

包含任何 ignore 中符号的替换将被忽略。

list:布尔值,(默认为 True)

返回表达式列表或者具有与输入相同类型的输出(当为 False 时)。

返回:

replacements:(符号,表达式)对列表

所有被替换的共同子表达式。此列表中较早的子表达式可能会出现在此列表较晚的子表达式中。

reduced_exprs:SymPy 表达式的列表

具有上述所有替换的减少表达式。

示例

>>> from sympy import cse, SparseMatrix
>>> from sympy.abc import x, y, z, w
>>> cse(((w + x + y + z)*(w + y + z))/(w + x)**3)
([(x0, y + z), (x1, w + x)], [(w + x0)*(x0 + x1)/x1**3]) 

使用递归替换的表达式列表:

>>> m = SparseMatrix([x + y, x + y + z])
>>> cse([(x+y)**2, x + y + z, y + z, x + z + y, m])
([(x0, x + y), (x1, x0 + z)], [x0**2, x1, y + z, x1, Matrix([
[x0],
[x1]])]) 

注意:输入矩阵的类型和可变性保留。

>>> isinstance(_[1][-1], SparseMatrix)
True 

用户可能禁止包含特定符号的替换:

>>> cse([y**2*(x + 1), 3*y**2*(x + 1)], ignore=(y,))
([(x0, x + 1)], [x0*y**2, 3*x0*y**2]) 

即使只有一个表达式,默认情况下减少后的返回值也是一个列表。 list 标志保留输出中输入的类型:

>>> cse(x)
([], [x])
>>> cse(x, list=False)
([], x) 

代码生成

原文:docs.sympy.org/latest/reference/public/codegeneration/index.html

目录

  • 代码生成

代码生成

原始文档:docs.sympy.org/latest/modules/codegen.html

SymPy 的多个子模块允许直接从 SymPy 表达式生成可直接编译和执行的代码,支持多种不同的编程语言。此外,还有一些函数生成 Python 可导入的对象,能够高效地评估 SymPy 表达式。

我们将从简要介绍构成 SymPy 代码生成功能的组件开始。

介绍

有四个主要的抽象层次:

expression
   |
code printers
   |
code generators
   |
autowrap 

sympy.utilities.autowrap 使用了 codegen,而 codegen 又使用了代码打印机。sympy.utilities.autowrap 实现了一步到位:在同一个 Python 进程中,它让您能够从 SymPy 表达式转换为数值函数。 Codegen 是实际的代码生成,即编译和以后使用,或者包含在某个更大的项目中。

代码打印机将 SymPy 对象翻译成实际的代码,如 abs(x) -> fabs(x)(用于 C)。

在许多情况下,代码打印机并不输出最优的代码。例如,在 C 中,幂运算 x**2 输出为 pow(x, 2) 而不是 x*x。其他优化(如数学简化)应该在代码打印机之前进行。

目前,在此链中自动应用 sympy.simplify.cse_main.cse() 尚未发生。理想情况下,它应该在代码生成级别或其上某处发生。

我们将逐级介绍以下内容。

以下三行将用于设置每个示例:

>>> from sympy import *
>>> init_printing(use_unicode=True)
>>> from sympy.abc import a, e, k, n, r, t, x, y, z, T, Z
>>> from sympy.abc import beta, omega, tau
>>> f, g = symbols('f, g', cls=Function) 

代码打印机(sympy.printing)

这里是代码生成的核心;SymPy 的翻译实际上更像是 Python 的轻量级代码生成版本,而 Python (sympy.printing.pycode.pycode()) 和 sympy.printing.lambdarepr.lambdarepr(),支持许多库(如 NumPy),以及 Aesara (sympy.printing.aesaracode.aesara_function())。代码打印机是 SymPy 中其他打印机(如字符串打印机、美观打印机等)的特殊情况。

一个重要的区别是,代码打印机必须处理赋值(使用 sympy.codegen.ast.Assignment 对象)。这作为代码打印机及其 codegen 模块的构建块。以下是在 C 代码中使用 Assignment 的示例:

>>> from sympy.codegen.ast import Assignment
>>> print(ccode(Assignment(x, y + 1)))
x = y + 1; 

这里是另一个打印 SymPy 表达式 C 版本的简单示例:

>>> expr = (Rational(-1, 2) * Z * k * (e**2) / r)
>>> expr
 2
-Z⋅e ⋅k
────────
 2⋅r
>>> ccode(expr)
-1.0/2.0*Z*pow(e, 2)*k/r
>>> from sympy.codegen.ast import real, float80
>>> ccode(expr, assign_to="E", type_aliases={real: float80})
E = -1.0L/2.0L*Z*powl(e, 2)*k/r; 

要生成使用例如 C99 标准提供的一些数学函数的代码,我们需要从sympy.codegen.cfunctions导入函数:

>>> from sympy.codegen.cfunctions import expm1
>>> ccode(expm1(x), standard='C99')
expm1(x) 

Piecewise表达式将转换为条件语句。如果提供了assign_to变量,则创建一个 if 语句,否则使用三元运算符。请注意,如果Piecewise缺少由(expr, True)表示的默认项,则会引发错误。这是为了防止生成一个可能不会评估为任何内容的表达式。一个Piecewise的用例:

>>> expr = Piecewise((x + 1, x > 0), (x, True))
>>> print(fcode(expr, tau))
 if (x > 0) then
 tau = x + 1
 else
 tau = x
 end if 

各种打印机通常也很好地支持Indexed对象。使用contract=True这些表达式将被转换为循环,而contract=False则只会打印应该循环的赋值表达式:

>>> len_y = 5
>>> mat_1 = IndexedBase('mat_1', shape=(len_y,))
>>> mat_2 = IndexedBase('mat_2', shape=(len_y,))
>>> Dy = IndexedBase('Dy', shape=(len_y-1,))
>>> i = Idx('i', len_y-1)
>>> eq = Eq(Dy[i], (mat_1[i+1] - mat_1[i]) / (mat_2[i+1] - mat_2[i]))
>>> print(jscode(eq.rhs, assign_to=eq.lhs, contract=False))
Dy[i] = (mat_1[i + 1] - mat_1[i])/(mat_2[i + 1] - mat_2[i]);
>>> Res = IndexedBase('Res', shape=(len_y,))
>>> j = Idx('j', len_y)
>>> eq = Eq(Res[j], mat_1[j]*mat_2[j])
>>> print(jscode(eq.rhs, assign_to=eq.lhs, contract=True))
for (var j=0; j<5; j++){
 Res[j] = 0;
}
for (var j=0; j<5; j++){
 for (var j=0; j<5; j++){
 Res[j] = Res[j] + mat_1[j]*mat_2[j];
 }
}
>>> print(jscode(eq.rhs, assign_to=eq.lhs, contract=False))
Res[j] = mat_1[j]*mat_2[j]; 

可以通过将“type”:“function”字典传递给user_functions关键字来为某些类型定义自定义打印。或者,字典值可以是元组列表,即[(argument_test, cfunction_string)]。这可以用于调用自定义 Octave 函数:

>>> custom_functions = {
...   "f": "existing_octave_fcn",
...   "g": [(lambda x: x.is_Matrix, "my_mat_fcn"),
...         (lambda x: not x.is_Matrix, "my_fcn")]
... }
>>> mat = Matrix([[1, x]])
>>> octave_code(f(x) + g(x) + g(mat), user_functions=custom_functions)
existing_octave_fcn(x) + my_fcn(x) + my_mat_fcn([1 x]) 

Mathematica 代码打印机示例:

>>> x_ = Function('x')
>>> expr = x_(n*T) * sin((t - n*T) / T)
>>> expr = expr / ((-T*n + t) / T)
>>> expr
 ⎛-T⋅n + t⎞
T⋅x(T⋅n)⋅sin⎜────────⎟
 ⎝   T    ⎠
──────────────────────
 -T⋅n + t

>>> expr = summation(expr, (n, -1, 1))
>>> mathematica_code(expr)
T*(x[-T]*Sin[(T + t)/T]/(T + t) + x[T]*Sin[(-T + t)/T]/(-T + t) + x[0]*Sin[t/T]/t) 

我们可以通过我们支持的不同语言中的常见表达式并看看它是如何工作的:

>>> k, g1, g2, r, I, S = symbols("k, gamma_1, gamma_2, r, I, S")
>>> expr = k * g1 * g2 / (r**3)
>>> expr = expr * 2 * I * S * (3 * (cos(beta))**2 - 1) / 2
>>> expr
 ⎛     2       ⎞
I⋅S⋅γ₁⋅γ₂⋅k⋅⎝3⋅cos (β) - 1⎠
───────────────────────────
 3
 r
>>> print(jscode(expr, assign_to="H_is"))
H_is = I*S*gamma_1*gamma_2*k*(3*Math.pow(Math.cos(beta), 2) - 1)/Math.pow(r, 3);
>>> print(ccode(expr, assign_to="H_is", standard='C89'))
H_is = I*S*gamma_1*gamma_2*k*(3*pow(cos(beta), 2) - 1)/pow(r, 3);
>>> print(fcode(expr, assign_to="H_is"))
 H_is = I*S*gamma_1*gamma_2*k*(3*cos(beta)**2 - 1)/r**3
>>> print(julia_code(expr, assign_to="H_is"))
H_is = I .* S .* gamma_1 .* gamma_2 .* k .* (3 * cos(beta) .^ 2 - 1) ./ r .^ 3
>>> print(octave_code(expr, assign_to="H_is"))
H_is = I.*S.*gamma_1.*gamma_2.*k.*(3*cos(beta).² - 1)./r.³;
>>> print(rust_code(expr, assign_to="H_is"))
H_is = I*S*gamma_1*gamma_2*k*(3*beta.cos().powi(2) - 1)/r.powi(3);
>>> print(mathematica_code(expr))
I*S*gamma_1*gamma_2*k*(3*Cos[beta]² - 1)/r³ 

Codegen(sympy.utilities.codegen)

此模块处理从 SymPy 表达式创建可编译代码。这比 autowrap 更低级,因为它实际上不尝试编译代码,但比打印机更高级,因为它生成可编译的文件(包括头文件),而不仅仅是代码片段。

在这里友好的函数是codegenmake_routinecodegen接受(variable, expression)对的列表和语言(支持 C、F95 和 Octave/Matlab)。它返回一个代码文件和一个头文件的字符串,对应于相关语言。这些变量被创建为返回表达式值的函数输出。

注意

可调用的codegen不会自动存在于 sympy 命名空间中,要使用它,必须首先从sympy.utilities.codegen导入codegen

例如:

>>> from sympy.utilities.codegen import codegen
>>> length, breadth, height = symbols('length, breadth, height')
>>> [(c_name, c_code), (h_name, c_header)] = \
... codegen(('volume', length*breadth*height), "C99", "test",
...         header=False, empty=False)
>>> print(c_name)
test.c
>>> print(c_code)
#include "test.h"
#include <math.h>
double volume(double breadth, double height, double length) {
 double volume_result;
 volume_result = breadth*height*length;
 return volume_result;
}
>>> print(h_name)
test.h
>>> print(c_header)
#ifndef PROJECT__TEST__H
#define PROJECT__TEST__H
double volume(double breadth, double height, double length);
#endif 

各种标志可以让您修改codegen中的事物。使用project可以变化项目名称以用于预处理指令。在global_vars参数中列出的全局变量将不会显示为函数参数。

language是一个不区分大小写的字符串,表示源代码语言。目前支持CF95OctaveOctave生成与 Octave 和 Matlab 兼容的代码。

header为 True 时,在每个源文件的顶部会写入一个头部。当empty为 True 时,使用空行来结构化代码。使用argument_sequence可以定义首选顺序的例程参数序列。

prefix定义了包含源代码的文件名称的前缀。如果省略,则使用第一个name_expr元组的名称。

to_files为 True 时,代码将被写入一个或多个带有给定前缀的文件。

这里是一个示例:

>>> [(f_name, f_code), header] = codegen(("volume", length*breadth*height),
...     "F95", header=False, empty=False, argument_sequence=(breadth, length),
...     global_vars=(height,))
>>> print(f_code)
REAL*8 function volume(breadth, length)
implicit none
REAL*8, intent(in) :: breadth
REAL*8, intent(in) :: length
volume = breadth*height*length
end function 

方法make_routine创建一个Routine对象,表示一组表达式的评估例程。这仅适用于 CodeGen 对象内部使用,作为从 SymPy 表达式到生成代码的中间表示。不建议自己创建Routine对象。您应该使用make_routine方法。make_routine反过来调用 CodeGen 对象的routine方法,具体取决于所选语言。这样创建表示赋值等的内部对象,并使用它们创建Routine类。

各种 codegen 对象,如RoutineVariable并非 SymPy 对象(它们不从 Basic 子类化)。

例如:

>>> from sympy.utilities.codegen import make_routine
>>> from sympy.physics.hydrogen import R_nl
>>> expr = R_nl(3, y, x, 6)
>>> routine = make_routine('my_routine', expr)
>>> [arg.result_var for arg in routine.results]   
[result₅₁₄₂₃₄₁₆₈₁₃₉₇₇₁₉₄₂₈]
>>> [arg.expr for arg in routine.results]
⎡                __________                                          ⎤
⎢          y    ╱ (2 - y)!   -2⋅x                                    ⎥
⎢4⋅√6⋅(4⋅x) ⋅  ╱  ──────── ⋅ℯ    ⋅assoc_laguerre(2 - y, 2⋅y + 1, 4⋅x)⎥
⎢            ╲╱   (y + 3)!                                           ⎥
⎢────────────────────────────────────────────────────────────────────⎥
⎣                                 3>>> [arg.name for arg in routine.arguments]
[x, y] 

另一个更复杂的示例,混合指定和自动分配的名称。还有矩阵输出:

>>> routine = make_routine('fcn', [x*y, Eq(a, 1), Eq(r, x + r), Matrix([[x, 2]])])
>>> [arg.result_var for arg in routine.results]   
[result_5397460570204848505]
>>> [arg.expr for arg in routine.results]
[x⋅y]
>>> [arg.name for arg in routine.arguments]   
[x, y, a, r, out_8598435338387848786] 

我们可以更仔细地检查各种参数:

>>> from sympy.utilities.codegen import (InputArgument, OutputArgument,
...                                      InOutArgument)
>>> [a.name for a in routine.arguments if isinstance(a, InputArgument)]
[x, y]

>>> [a.name for a in routine.arguments if isinstance(a, OutputArgument)]  
[a, out_8598435338387848786]
>>> [a.expr for a in routine.arguments if isinstance(a, OutputArgument)]
[1, [x  2]]

>>> [a.name for a in routine.arguments if isinstance(a, InOutArgument)]
[r]
>>> [a.expr for a in routine.arguments if isinstance(a, InOutArgument)]
[r + x] 

完整的 API 参考可以在这里查看。

Autowrap

Autowrap 自动生成代码,将其写入磁盘,编译它并导入到当前会话中。本模块的主要功能是autowrapbinary_functionufuncify

它还会自动将包含Indexed对象的表达式转换为求和。类 IndexedBase、Indexed 和 Idx 表示矩阵元素 M[i, j]。有关更多信息,请参见 Tensor。

autowrap使用 f2py 或 Cython 创建包装器并创建数值函数。

注意

可调用的autowrap不会自动放置在 sympy 命名空间中,要使用它,您必须先从sympy.utilities.autowrap导入autowrap

autowrap返回的可调用函数是一个二进制的 Python 函数,而不是 SymPy 对象。例如:

>>> from sympy.utilities.autowrap import autowrap
>>> expr = ((x - y + z)**(13)).expand()
>>> binary_func = autowrap(expr)    
>>> binary_func(1, 4, 2)    
-1.0 

autowrap()提供的各种标志有助于修改方法提供的服务。参数tempdir告诉 autowrap 在特定目录中编译代码,并在完成后保留文件。例如:

>>> from sympy.utilities.autowrap import autowrap
>>> from sympy.physics.qho_1d import psi_n
>>> x_ = IndexedBase('x')
>>> y_ = IndexedBase('y')
>>> m = symbols('m', integer=True)
>>> i = Idx('i', m)
>>> qho = autowrap(Eq(y_[i], psi_n(0, x_[i], m, omega)), tempdir='/tmp') 

检查指定目录中的 Fortran 源代码揭示了这一点:

subroutine autofunc(m, omega, x, y)
implicit none
INTEGER*4, intent(in) :: m
REAL*8, intent(in) :: omega
REAL*8, intent(in), dimension(1:m) :: x
REAL*8, intent(out), dimension(1:m) :: y
INTEGER*4 :: i

REAL*8, parameter :: hbar = 1.05457162d-34
REAL*8, parameter :: pi = 3.14159265358979d0
do i = 1, m
   y(i) = (m*omega)**(1.0d0/4.0d0)*exp(-4.74126166983329d+33*m*omega*x(i &
         )**2)/(hbar**(1.0d0/4.0d0)*pi**(1.0d0/4.0d0))
end do

end subroutine 

使用参数args与其一起改变参数序列:

>>> eq = Eq(y_[i], psi_n(0, x_[i], m, omega))
>>> qho = autowrap(eq, tempdir='/tmp', args=[y, x, m, omega]) 

产生:

subroutine autofunc(y, x, m, omega)
implicit none
INTEGER*4, intent(in) :: m
REAL*8, intent(in) :: omega
REAL*8, intent(out), dimension(1:m) :: y
REAL*8, intent(in), dimension(1:m) :: x
INTEGER*4 :: i

REAL*8, parameter :: hbar = 1.05457162d-34
REAL*8, parameter :: pi = 3.14159265358979d0
do i = 1, m
   y(i) = (m*omega)**(1.0d0/4.0d0)*exp(-4.74126166983329d+33*m*omega*x(i &
         )**2)/(hbar**(1.0d0/4.0d0)*pi**(1.0d0/4.0d0))
end do

end subroutine 

参数verbose是布尔值,可选,如果为 True,则 autowrap 不会使命令行后端静音。这对调试非常有帮助。

参数languagebackend用于将默认值从Fortranf2py更改为CCython。参数 helpers 用于定义主表达式所需的辅助表达式。如果主表达式需要调用特殊函数,则应将其放入 helpers 可迭代对象中。Autowrap 将确保编译的主表达式可以链接到帮助程序例程。项目应该是带有(<function_name>,<sympy_expression>,)的元组。必须为辅助例程提供参数序列。

autowrap 层面可用的另一种方法是 binary_function。它返回一个 sympy 函数。其优势在于,与 SymPy 速度相比,我们可以得到非常快速的函数。这是因为我们将使用带有 SymPy 属性和方法的编译函数。一个例子:

>>> from sympy.utilities.autowrap import binary_function
>>> from sympy.physics.hydrogen import R_nl
>>> psi_nl = R_nl(1, 0, a, r)
>>> f = binary_function('f', psi_nl)    
>>> f(a, r).evalf(3, subs={a: 1, r: 2})  
0.766 

虽然 NumPy 操作对于矢量化数据非常高效,但在连锁操作时有时会产生不必要的成本。考虑以下操作

>>> x = get_numpy_array(...) 
>>> y = sin(x) / x 

sin/ 运算符调用执行紧密循环的 C 例程。得到的计算看起来像这样

for(int  i  =  0;  i  <  n;  i++)
{
  temp[i]  =  sin(x[i]);
}
for(int  i  =  i;  i  <  n;  i++)
{
  y[i]  =  temp[i]  /  x[i];
} 

这略微不够优化,因为

  1. 我们分配了额外的 temp 数组

  2. 当一次就足够时,我们对 x 内存进行了两次遍历

更好的解决方案将两个逐元素操作融合为单个循环

for(int  i  =  i;  i  <  n;  i++)
{
  y[i]  =  sin(x[i])  /  x[i];
} 

像 NumPy 这样的静态编译项目无法利用这些优化。幸运的是,SymPy 能够生成高效的低级别 C 或 Fortran 代码。然后,它可以依赖于像 Cythonf2py 这样的项目来编译并重新连接该代码回到 Python。幸运的是,这个过程是自动化的,希望利用这些代码生成的 SymPy 用户应该调用 ufuncify 函数。

ufuncify 是 Aurowrap 模块的第三种可用方法。它基本上暗示了‘通用函数’,并遵循了 NumPy 设定的理念。与 autowrap 相比,ufuncify 的主要优点是允许数组作为参数,并且可以逐元素地进行操作。按照 NumPy 的数组广播规则逐元素进行的核心操作。查看 了解更多信息。

>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x 
>>> from sympy.utilities.autowrap import ufuncify
>>> f = ufuncify([x], expr) 

此函数 f 消耗并返回一个 NumPy 数组。通常情况下,ufuncify 的性能至少与 lambdify 相当。如果表达式复杂,则 ufuncify 通常明显优于 NumPy 支持的解决方案。Jensen 在这个主题上有一篇很好的 博文

让我们看一个进行一些数量分析的示例:

>>> from sympy.physics.hydrogen import R_nl
>>> expr = R_nl(3, 1, x, 6)
>>> expr
 -2⋅x
8⋅x⋅(4 - 4⋅x)⋅ℯ
───────────────────
 3 

lambdify 函数将 SymPy 表达式转换为 Python 函数,利用各种数值库。默认情况下,lambdify 依赖于 math 标准库中的实现。自然地,原始的 Python 比 SymPy 更快。但它也支持 mpmath 和最显著的是 numpy。使用 NumPy 库使生成的函数能够访问由编译的 C 代码支持的强大的矢量化 ufuncs。

让我们比较速度:

>>> from sympy.utilities.autowrap import ufuncify
>>> from sympy.utilities.lambdify import lambdify
>>> fn_numpy = lambdify(x, expr, 'numpy')   
>>> fn_fortran = ufuncify([x], expr, backend='f2py')    
>>> from numpy import linspace  
>>> xx = linspace(0, 1, 5)  
>>> fn_numpy(xx)    
[ 0\.          1.21306132  0.98101184  0.44626032  0\.        ]
>>> fn_fortran(xx)  
[ 0\.          1.21306132  0.98101184  0.44626032  0\.        ]
>>> import timeit
>>> timeit.timeit('fn_numpy(xx)', 'from __main__ import fn_numpy, xx', number=10000)    
0.18891601900395472
>>> timeit.timeit('fn_fortran(xx)', 'from __main__ import fn_fortran, xx', number=10000)    
0.004707066000264604 

autowrap 可用的选项基本相同。

SymPy 还有其他有效的数值计算工具可用。参见 此 页面进行比较。

重写表达式的类和函数(sympy.codegen.rewriting)

有助于重写表达式以进行优化代码生成的类和函数。某些语言(或其标准),如 C99,提供了专门的数学函数以获得更好的性能和/或精度。

使用此模块中的optimize函数以及一系列规则(表示为Optimization实例),可以为此目的重写表达式:

>>> from sympy import Symbol, exp, log
>>> from sympy.codegen.rewriting import optimize, optims_c99
>>> x = Symbol('x')
>>> optimize(3*exp(2*x) - 3, optims_c99)
3*expm1(2*x)
>>> optimize(exp(2*x) - 1 - exp(-33), optims_c99)
expm1(2*x) - exp(-33)
>>> optimize(log(3*x + 3), optims_c99)
log1p(x) + log(3)
>>> optimize(log(2*x + 3), optims_c99)
log(2*x + 3) 

上面导入的optims_c99是包含以下实例的元组(可以从sympy.codegen.rewriting导入):

  • expm1_opt

  • log1p_opt

  • exp2_opt

  • log2_opt

  • log2const_opt

class sympy.codegen.rewriting.FuncMinusOneOptim(func, func_m_1, opportunistic=True)

专门用于计算“f(x) - 1”的 ReplaceOptim 特化函数。

参数:

函数:

减一的函数。

func_m_1:

专门用于评估func(x) - 1的函数。

机会主义:布尔值

当为True时,只要剩余数字项的数量减少,则应用转换。当为False时,仅当完全消除数字项时才应用转换。

解释

当 x 趋近于零时,以向一处收敛的数值函数通常最好通过专门的函数实现,以避免灾难性的取消。一个典型的例子是 C 标准库中的expm1(x),它计算的是exp(x) - 1。这种函数在其参数远小于一时能保留更多有效位数,相比之下,后续减一则无法保留这些位数。

示例

>>> from sympy import symbols, exp
>>> from sympy.codegen.rewriting import FuncMinusOneOptim
>>> from sympy.codegen.cfunctions import expm1
>>> x, y = symbols('x y')
>>> expm1_opt = FuncMinusOneOptim(exp, expm1)
>>> expm1_opt(exp(x) + 2*exp(5*y) - 3)
expm1(x) + 2*expm1(5*y) 
replace_in_Add(e)

作为第二个参数传递给 Basic.replace(…)

class sympy.codegen.rewriting.Optimization(cost_function=None, priority=1)

重写优化的抽象基类。

子类应实现__call__,接受一个表达式作为参数。

参数:

成本函数:返回数字的可调用对象

优先级:数字

class sympy.codegen.rewriting.ReplaceOptim(query, value, **kwargs)

在表达式上调用 replace 进行重写优化。

参数:

查询:

替换时传递的第一个参数。

值:

替换的第二个传递参数。

解释

可以将该实例用作函数,适用于表达式,它将应用于replace方法(参见sympy.core.basic.Basic.replace())。

示例

>>> from sympy import Symbol
>>> from sympy.codegen.rewriting import ReplaceOptim
>>> from sympy.codegen.cfunctions import exp2
>>> x = Symbol('x')
>>> exp2_opt = ReplaceOptim(lambda p: p.is_Pow and p.base == 2,
...     lambda p: exp2(p.exp))
>>> exp2_opt(2**x)
exp2(x) 
sympy.codegen.rewriting.create_expand_pow_optimization(limit, *, base_req=<function <lambda>>)

Pow展开创建一个ReplaceOptim实例。

参数:

限制:整数

展开为乘法的最高幂次。

base_req:返回布尔值的函数

展开发生的基本要求,默认返回基数的is_symbol属性。

解释

展开的要求是基数必须是一个符号,并且指数必须是一个整数(且小于或等于limit)。

示例

>>> from sympy import Symbol, sin
>>> from sympy.codegen.rewriting import create_expand_pow_optimization
>>> x = Symbol('x')
>>> expand_opt = create_expand_pow_optimization(3)
>>> expand_opt(x**5 + x**3)
x**5 + x*x*x
>>> expand_opt(x**5 + x**3 + sin(x)**3)
x**5 + sin(x)**3 + x*x*x
>>> opt2 = create_expand_pow_optimization(3, base_req=lambda b: not b.is_Function)
>>> opt2((x+1)**2 + sin(x)**2)
sin(x)**2 + (x + 1)*(x + 1) 
sympy.codegen.rewriting.optimize(expr, optimizations)

对表达式应用优化。

参数:

表达式:表达式

优化Optimization实例的可迭代对象

优化将根据priority(最高优先级在前)排序。

示例

>>> from sympy import log, Symbol
>>> from sympy.codegen.rewriting import optims_c99, optimize
>>> x = Symbol('x')
>>> optimize(log(x+3)/log(2) + log(x**2 + 1), optims_c99)
log1p(x**2) + log2(x + 3) 

用于矩阵操作的额外 AST 节点。此模块中的节点旨在表示无法通过 SymPy 表达式表示的代码生成目标语言中的矩阵表达式的优化。

例如,我们可以使用sympy.codegen.rewriting.optimize()sympy.codegen.rewriting提供的matin_opt优化来在特定假设下转换矩阵乘法:

>>> from sympy import symbols, MatrixSymbol
>>> n = symbols('n', integer=True)
>>> A = MatrixSymbol('A', n, n)
>>> x = MatrixSymbol('x', n, 1)
>>> expr = A**(-1) * x
>>> from sympy import assuming, Q
>>> from sympy.codegen.rewriting import matinv_opt, optimize
>>> with assuming(Q.fullrank(A)):
...     optimize(expr, [matinv_opt])
MatrixSolve(A, vector=x) 
class sympy.codegen.matrix_nodes.MatrixSolve(*args, **kwargs)

代表一个解线性矩阵方程的操作。

参数:

matrix : MatrixSymbol

表示线性方程中变量系数的矩阵。该矩阵必须是方阵且满秩(即所有列必须线性独立),才能进行有效的求解操作。

vector : MatrixSymbol

表示在matrix中表示的方程的解的单列矩阵。

示例

>>> from sympy import symbols, MatrixSymbol
>>> from sympy.codegen.matrix_nodes import MatrixSolve
>>> n = symbols('n', integer=True)
>>> A = MatrixSymbol('A', n, n)
>>> x = MatrixSymbol('x', n, 1)
>>> from sympy.printing.numpy import NumPyPrinter
>>> NumPyPrinter().doprint(MatrixSolve(A, x))
'numpy.linalg.solve(A, x)'
>>> from sympy import octave_code
>>> octave_code(MatrixSolve(A, x))
'A \\ x' 
```  ## 使用近似简化表达式的工具(sympy.codegen.approximations)

```py
class sympy.codegen.approximations.SeriesApprox(bounds, reltol, max_order=4, n_point_checks=4, **kwargs)

通过将它们展开为级数来近似函数。

参数:

bounds : dict

将表达式映射到长度为 2 的边界元组(低,高)。

reltol : number

相对于所有边界中的最大下界时要忽略术语。

max_order : int

包括在级数展开中的最大阶数

n_point_checks : int(偶数)

在离散点(线性间隔在变量的边界上)上检查展开的有效性(相对于 reltol)。在此数值检查中使用的点数由此数字给出。

示例

>>> from sympy import sin, pi
>>> from sympy.abc import x, y
>>> from sympy.codegen.rewriting import optimize
>>> from sympy.codegen.approximations import SeriesApprox
>>> bounds = {x: (-.1, .1), y: (pi-1, pi+1)}
>>> series_approx2 = SeriesApprox(bounds, reltol=1e-2)
>>> series_approx3 = SeriesApprox(bounds, reltol=1e-3)
>>> series_approx8 = SeriesApprox(bounds, reltol=1e-8)
>>> expr = sin(x)*sin(y)
>>> optimize(expr, [series_approx2])
x*(-y + (y - pi)**3/6 + pi)
>>> optimize(expr, [series_approx3])
(-x**3/6 + x)*sin(y)
>>> optimize(expr, [series_approx8])
sin(x)*sin(y) 
class sympy.codegen.approximations.SumApprox(bounds, reltol, **kwargs)

通过忽略小术语来近似和。

参数:

bounds : dict

将表达式映射到长度为 2 的边界元组(低,高)。

reltol : number

相对于所有边界中的最大下界时要忽略术语。

解释

如果术语是可以确定为单调的表达式,则将这些表达式的边界添加进去。

示例

>>> from sympy import exp
>>> from sympy.abc import x, y, z
>>> from sympy.codegen.rewriting import optimize
>>> from sympy.codegen.approximations import SumApprox
>>> bounds = {x: (-1, 1), y: (1000, 2000), z: (-10, 3)}
>>> sum_approx3 = SumApprox(bounds, reltol=1e-3)
>>> sum_approx2 = SumApprox(bounds, reltol=1e-2)
>>> sum_approx1 = SumApprox(bounds, reltol=1e-1)
>>> expr = 3*(x + y + exp(z))
>>> optimize(expr, [sum_approx3])
3*(x + y + exp(z))
>>> optimize(expr, [sum_approx2])
3*y + 3*exp(z)
>>> optimize(expr, [sum_approx1])
3*y 
```  ## 抽象语法树类(sympy.codegen.ast)

用于表示完整函数/模块的 AST 类型。

大多数类型都很小,仅用作 AST 中的标记。下面的树形图说明了 AST 类型之间的关系。

### AST 类型树

```py
*Basic*
     |
     |
 CodegenAST
     |
     |--->AssignmentBase
     |             |--->Assignment
     |             |--->AugmentedAssignment
     |                                    |--->AddAugmentedAssignment
     |                                    |--->SubAugmentedAssignment
     |                                    |--->MulAugmentedAssignment
     |                                    |--->DivAugmentedAssignment
     |                                    |--->ModAugmentedAssignment
     |
     |--->CodeBlock
     |
     |
     |--->Token
              |--->Attribute
              |--->For
              |--->String
              |       |--->QuotedString
              |       |--->Comment
              |--->Type
              |       |--->IntBaseType
              |       |              |--->_SizedIntType
              |       |                               |--->SignedIntType
              |       |                               |--->UnsignedIntType
              |       |--->FloatBaseType
              |                        |--->FloatType
              |                        |--->ComplexBaseType
              |                                           |--->ComplexType
              |--->Node
              |       |--->Variable
              |       |           |---> Pointer
              |       |--->FunctionPrototype
              |                            |--->FunctionDefinition
              |--->Element
              |--->Declaration
              |--->While
              |--->Scope
              |--->Stream
              |--->Print
              |--->FunctionCall
              |--->BreakToken
              |--->ContinueToken
              |--->NoneToken
              |--->Return 

预定义类型

sympy.codegen.ast模块提供了多种Type实例供方便使用。也许最常见的两种用于代码生成(数值代码)的是float32float64(分别称为单精度和双精度)。此外,还有精确的通用类型版本(在打印时选择底层数据类型):realintegercomplex_bool_

其他定义的Type实例为:

  • intc:C 中使用的整数类型。

  • intp:C 中使用的无符号整数类型。

  • int8int16int32int64:n 位整数。

  • uint8uint16uint32uint64:n 位无符号整数。

  • float80:在现代 x86/amd64 硬件上称为“扩展精度”。

  • complex64:由两个 float32 数字表示的复数。

  • complex128:由两个 float64 数字表示的复数

使用节点

可以使用 AST 节点构造简单的算法。让我们构造一个应用牛顿法的循环:

>>> from sympy import symbols, cos
>>> from sympy.codegen.ast import While, Assignment, aug_assign, Print, QuotedString
>>> t, dx, x = symbols('tol delta val')
>>> expr = cos(x) - x**3
>>> whl = While(abs(dx) > t, [
...     Assignment(dx, -expr/expr.diff(x)),
...     aug_assign(x, '+', dx),
...     Print([x])
... ])
>>> from sympy import pycode
>>> py_str = pycode(whl)
>>> print(py_str)
while (abs(delta) > tol):
 delta = (val**3 - math.cos(val))/(-3*val**2 - math.sin(val))
 val += delta
 print(val)
>>> import math
>>> tol, val, delta = 1e-5, 0.5, float('inf')
>>> exec(py_str)
1.1121416371
0.909672693737
0.867263818209
0.865477135298
0.865474033111
>>> print('%3.1g' % (math.cos(val) - val**3))
-3e-11 

如果我们想要为相同的 while 循环生成 Fortran 代码,我们只需调用 fcode

>>> from sympy import fcode
>>> print(fcode(whl, standard=2003, source_format='free'))
do while (abs(delta) > tol)
 delta = (val**3 - cos(val))/(-3*val**2 - sin(val))
 val = val + delta
 print *, val
end do 

有一个函数在 sympy.codegen.algorithms 中构造循环(或完整函数)。

class sympy.codegen.ast.Assignment(lhs, rhs)

代表用于代码生成的变量赋值。

参数:

lhs:Expr

SymPy 对象,表示表达式的左手边。这些应该是单一的对象,例如在编写代码时使用的对象。显著的类型包括 Symbol、MatrixSymbol、MatrixElement 和 Indexed。支持这些类型的子类也是支持的。

rhs:Expr

SymPy 对象,表示表达式的右手边。可以是任何类型,只要其形状与左手边相对应。例如,Matrix 类型可以分配给 MatrixSymbol,但不能分配给 Symbol,因为维度不会对齐。

示例

>>> from sympy import symbols, MatrixSymbol, Matrix
>>> from sympy.codegen.ast import Assignment
>>> x, y, z = symbols('x, y, z')
>>> Assignment(x, y)
Assignment(x, y)
>>> Assignment(x, 0)
Assignment(x, 0)
>>> A = MatrixSymbol('A', 1, 3)
>>> mat = Matrix([x, y, z]).T
>>> Assignment(A, mat)
Assignment(A, Matrix([[x, y, z]]))
>>> Assignment(A[0, 1], x)
Assignment(A[0, 1], x) 
class sympy.codegen.ast.AssignmentBase(lhs, rhs)

赋值和增强赋值的抽象基类。

属性:

opstr

用于赋值操作符的符号,例如“=”,“+=”等。

class sympy.codegen.ast.Attribute(possibly parametrized)

用于 sympy.codegen.ast.Node 的实例(它将 attrs 作为 Attribute 的实例)。

参数:

name:str

parameters:Tuple

示例

>>> from sympy.codegen.ast import Attribute
>>> volatile = Attribute('volatile')
>>> volatile
volatile
>>> print(repr(volatile))
Attribute(String('volatile'))
>>> a = Attribute('foo', [1, 2, 3])
>>> a
foo(1, 2, 3)
>>> a.parameters == (1, 2, 3)
True 
class sympy.codegen.ast.AugmentedAssignment(lhs, rhs)

增强赋值的基类。

属性:

binopstr

用于赋值操作中应用的二元操作符的符号,例如“+”,“*”等。

class sympy.codegen.ast.BreakToken(*args, **kwargs)

表示 C/Python 中的 ‘break’(Fortran 中的 ‘exit’)。

使用预定义的实例 break_ 或手动实例化。

示例

>>> from sympy import ccode, fcode
>>> from sympy.codegen.ast import break_
>>> ccode(break_)
'break'
>>> fcode(break_, source_format='free')
'exit' 
class sympy.codegen.ast.CodeBlock(*args)

代表代码块。

解释

目前仅支持赋值。这个限制将来会解除。

此对象的有用属性包括:

left_hand_sides

按顺序的赋值的左手边的元组。

left_hand_sides

按顺序的右手边的赋值的元组。

free_symbols:右侧表达式的自由符号

在赋值的左手边未出现的符号。

此对象的有用方法包括:

topological_sort

类方法。返回一个按照变量被赋值前使用的顺序排序的代码块。

cse

返回一个新的代码块,消除常见子表达式并将其作为赋值语句提取出来。

示例

>>> from sympy import symbols, ccode
>>> from sympy.codegen.ast import CodeBlock, Assignment
>>> x, y = symbols('x y')
>>> c = CodeBlock(Assignment(x, 1), Assignment(y, x + 1))
>>> print(ccode(c))
x = 1;
y = x + 1; 
cse(symbols=None, optimizations=None, postprocess=None, order='canonical')

返回一个新的代码块,消除常见的子表达式。

解释

查看 sympy.simplify.cse_main.cse() 的文档字符串获取更多信息。

示例

>>> from sympy import symbols, sin
>>> from sympy.codegen.ast import CodeBlock, Assignment
>>> x, y, z = symbols('x y z') 
>>> c = CodeBlock(
...     Assignment(x, 1),
...     Assignment(y, sin(x) + 1),
...     Assignment(z, sin(x) - 1),
... )
...
>>> c.cse()
CodeBlock(
 Assignment(x, 1),
 Assignment(x0, sin(x)),
 Assignment(y, x0 + 1),
 Assignment(z, x0 - 1)
) 
classmethod topological_sort(assignments)

返回一个按拓扑顺序排序的代码块,以便变量在使用之前被赋值。

示例

尽可能保持现有的赋值顺序。

此函数假设变量只被分配一次。

这是一个类构造函数,因此当变量在分配之前被使用时,默认构造函数可以报错。

>>> from sympy import symbols
>>> from sympy.codegen.ast import CodeBlock, Assignment
>>> x, y, z = symbols('x y z') 
>>> assignments = [
...     Assignment(x, y + z),
...     Assignment(y, z + 1),
...     Assignment(z, 2),
... ]
>>> CodeBlock.topological_sort(assignments)
CodeBlock(
 Assignment(z, 2),
 Assignment(y, z + 1),
 Assignment(x, y + z)
) 
class sympy.codegen.ast.Comment(*args, **kwargs)

表示一个注释。

class sympy.codegen.ast.ComplexType(*args, **kwargs)

表示复杂的浮点数。

class sympy.codegen.ast.ContinueToken(*args, **kwargs)

在 C/Python 中表示‘continue’(在 Fortran 中表示‘cycle’)

使用预制实例continue_或手动实例化。

示例

>>> from sympy import ccode, fcode
>>> from sympy.codegen.ast import continue_
>>> ccode(continue_)
'continue'
>>> fcode(continue_, source_format='free')
'cycle' 
class sympy.codegen.ast.Declaration(*args, **kwargs)

表示变量声明

参数:

variable : 变量

示例

>>> from sympy.codegen.ast import Declaration, NoneToken, untyped
>>> z = Declaration('z')
>>> z.variable.type == untyped
True
>>> # value is special NoneToken() which must be tested with == operator
>>> z.variable.value is None  # won't work
False
>>> z.variable.value == None  # not PEP-8 compliant
True
>>> z.variable.value == NoneToken()  # OK
True 
class sympy.codegen.ast.Element(*args, **kwargs)

数组中的元素(可能是 N 维)。

示例

>>> from sympy.codegen.ast import Element
>>> elem = Element('x', 'ijk')
>>> elem.symbol.name == 'x'
True
>>> elem.indices
(i, j, k)
>>> from sympy import ccode
>>> ccode(elem)
'x[i][j][k]'
>>> ccode(Element('x', 'ijk', strides='lmn', offset='o'))
'x[i*l + j*m + k*n + o]' 
class sympy.codegen.ast.FloatBaseType(*args, **kwargs)

表示浮点数类型。

cast_nocheck

别名为Float的浮点类型

class sympy.codegen.ast.FloatType(*args, **kwargs)

表示具有固定位宽的浮点类型。

基数 2 和一个符号位是默认的。

参数:

name : 字符串

类型的名称。

nbits : 整数

用于表示的位数(存储)。

nmant : 整数

用于表示尾数的位数。

nexp : 整数

用于表示尾数的位数。

示例

>>> from sympy import S
>>> from sympy.codegen.ast import FloatType
>>> half_precision = FloatType('f16', nbits=16, nmant=10, nexp=5)
>>> half_precision.max
65504
>>> half_precision.tiny == S(2)**-14
True
>>> half_precision.eps == S(2)**-10
True
>>> half_precision.dig == 3
True
>>> half_precision.decimal_dig == 5
True
>>> half_precision.cast_check(1.0)
1.0
>>> half_precision.cast_check(1e5)  
Traceback (most recent call last):
  ...
ValueError: Maximum value for data type smaller than new value. 
cast_nocheck(value)

强制转换,而不检查是否超出范围或子正常。

property decimal_dig

需要存储和加载而不会丢失的位数。

解释

需要保证两个连续的转换(浮点数 -> 文本 -> 浮点数)是幂等的十进制数字的数量。这在存储浮点值作为文本时,由于四舍五入误差而不想丢失精度时非常有用。

property dig

保证在文本中保留的十进制数字的数量。

当转换文本 -> 浮点数 -> 文本时,可以保证至少保留dig位数,以便于舍入或溢出。

property eps

1.0 与下一个可表示值之间的差异。

property max

可表示的最大值。

property max_exponent

最大的正数 n,使得 2 ** (n - 1)是可表示的有限值。

property min_exponent

最小的负数 n,使得 2 ** (n - 1)是有效的正规化数。

property tiny

最小的正规化值。

class sympy.codegen.ast.For(*args, **kwargs)

在代码中表示‘for-loop’。

表达式的形式:

“for target in iter:

body…”

参数:

target : 符号

iter : 可迭代体 body : CodeBlock 或可迭代

!当传入一个可迭代对象时,它用于实例化 CodeBlock。

示例

>>> from sympy import symbols, Range
>>> from sympy.codegen.ast import aug_assign, For
>>> x, i, j, k = symbols('x i j k')
>>> for_i = For(i, Range(10), [aug_assign(x, '+', i*j*k)])
>>> for_i  
For(i, iterable=Range(0, 10, 1), body=CodeBlock(
 AddAugmentedAssignment(x, i*j*k)
))
>>> for_ji = For(j, Range(7), [for_i])
>>> for_ji  
For(j, iterable=Range(0, 7, 1), body=CodeBlock(
 For(i, iterable=Range(0, 10, 1), body=CodeBlock(
 AddAugmentedAssignment(x, i*j*k)
 ))
))
>>> for_kji =For(k, Range(5), [for_ji])
>>> for_kji  
For(k, iterable=Range(0, 5, 1), body=CodeBlock(
 For(j, iterable=Range(0, 7, 1), body=CodeBlock(
 For(i, iterable=Range(0, 10, 1), body=CodeBlock(
 AddAugmentedAssignment(x, i*j*k)
 ))
 ))
)) 
class sympy.codegen.ast.FunctionCall(*args, **kwargs)

表示调用代码中的函数。

参数:

name : 字符串

function_args : 元组

示例

>>> from sympy.codegen.ast import FunctionCall
>>> from sympy import pycode
>>> fcall = FunctionCall('foo', 'bar baz'.split())
>>> print(pycode(fcall))
foo(bar, baz) 
class sympy.codegen.ast.FunctionDefinition(*args, **kwargs)

表示代码中的函数定义。

参数:

return_type : 类型

name : 字符串

parameters: 变量实例的可迭代对象

body : CodeBlock 或可迭代

attrs : 属性实例的可迭代对象

示例

>>> from sympy import ccode, symbols
>>> from sympy.codegen.ast import real, FunctionPrototype
>>> x, y = symbols('x y', real=True)
>>> fp = FunctionPrototype(real, 'foo', [x, y])
>>> ccode(fp)
'double foo(double x, double y)'
>>> from sympy.codegen.ast import FunctionDefinition, Return
>>> body = [Return(x*y)]
>>> fd = FunctionDefinition.from_FunctionPrototype(fp, body)
>>> print(ccode(fd))
double foo(double x, double y){
 return x*y;
} 
class sympy.codegen.ast.FunctionPrototype(*args, **kwargs)

表示函数原型

允许用户生成例如 C/C++中的前向声明。

参数:

return_type : 类型

name : 字符串

parameters: 变量实例的可迭代对象

attrs : 属性实例的可迭代对象

示例

>>> from sympy import ccode, symbols
>>> from sympy.codegen.ast import real, FunctionPrototype
>>> x, y = symbols('x y', real=True)
>>> fp = FunctionPrototype(real, 'foo', [x, y])
>>> ccode(fp)
'double foo(double x, double y)' 
class sympy.codegen.ast.IntBaseType(*args, **kwargs)

整数基本类型,不包含大小信息。

class sympy.codegen.ast.Node(*args, **kwargs)

Token 的子类,携带属性‘attrs’(元组)

示例

>>> from sympy.codegen.ast import Node, value_const, pointer_const
>>> n1 = Node([value_const])
>>> n1.attr_params('value_const')  # get the parameters of attribute (by name)
()
>>> from sympy.codegen.fnodes import dimension
>>> n2 = Node([value_const, dimension(5, 3)])
>>> n2.attr_params(value_const)  # get the parameters of attribute (by Attribute instance)
()
>>> n2.attr_params('dimension')  # get the parameters of attribute (by name)
(5, 3)
>>> n2.attr_params(pointer_const) is None
True 
attr_params(looking_for)

返回 self.attrs 中名为looking_for的属性的参数。

class sympy.codegen.ast.NoneToken(*args, **kwargs)

Python 的 NoneType 的 AST 等价物

Python 中对应的None的实例是none

示例

>>> from sympy.codegen.ast import none, Variable
>>> from sympy import pycode
>>> print(pycode(Variable('x').as_Declaration(value=none)))
x = None 
class sympy.codegen.ast.Pointer(*args, **kwargs)

表示指针。参见 Variable

示例

可以创建 Element 的实例:

>>> from sympy import Symbol
>>> from sympy.codegen.ast import Pointer
>>> i = Symbol('i', integer=True)
>>> p = Pointer('x')
>>> p[i+1]
Element(x, indices=(i + 1,)) 
class sympy.codegen.ast.Print(*args, **kwargs)

表示代码中的打印命令。

参数:

formatstring : 字符串

*args : Basic 实例(或通过 sympify 转换为这样的实例)

示例

>>> from sympy.codegen.ast import Print
>>> from sympy import pycode
>>> print(pycode(Print('x y'.split(), "coordinate: %12.5g  %12.5g\\n")))
print("coordinate: %12.5g %12.5g\n" % (x, y), end="") 
class sympy.codegen.ast.QuotedString(*args, **kwargs)

表示应使用引号打印的字符串。

class sympy.codegen.ast.Raise(*args, **kwargs)

在 Python 中打印为 ‘raise …’,在 C++ 中为 ‘throw …’。

class sympy.codegen.ast.Return(*args, **kwargs)

表示代码中的返回命令。

参数:

return : Basic

示例

>>> from sympy.codegen.ast import Return
>>> from sympy.printing.pycode import pycode
>>> from sympy import Symbol
>>> x = Symbol('x')
>>> print(pycode(Return(x)))
return x 
class sympy.codegen.ast.RuntimeError_(*args, **kwargs)

在 C++ 中表示 ‘std::runtime_error’,在 Python 中表示 ‘RuntimeError’。

注意后者不常见,你可能想使用例如 ValueError。

class sympy.codegen.ast.Scope(*args, **kwargs)

表示代码中的作用域。

参数:

body : CodeBlock 或可迭代对象

当传递一个可迭代对象时,它用于实例化一个 CodeBlock。

class sympy.codegen.ast.SignedIntType(*args, **kwargs)

表示有符号整数类型。

class sympy.codegen.ast.Stream(*args, **kwargs)

表示流。

有两个预定义的 Stream 实例 stdoutstderr

参数:

name : str

示例

>>> from sympy import pycode, Symbol
>>> from sympy.codegen.ast import Print, stderr, QuotedString
>>> print(pycode(Print(['x'], file=stderr)))
print(x, file=sys.stderr)
>>> x = Symbol('x')
>>> print(pycode(Print([QuotedString('x')], file=stderr)))  # print literally "x"
print("x", file=sys.stderr) 
class sympy.codegen.ast.String(*args, **kwargs)

表示字符串的 SymPy 对象。

不是表达式的原子对象(与 Symbol 相反)。

参数:

text : 字符串

示例

>>> from sympy.codegen.ast import String
>>> f = String('foo')
>>> f
foo
>>> str(f)
'foo'
>>> f.text
'foo'
>>> print(repr(f))
String('foo') 
class sympy.codegen.ast.Token(*args, **kwargs)

AST 类型的基类。

解释

_fields 中设置定义字段。属性(在 _fields 中定义)只允许包含 Basic 的实例(除非是原子的,见 String)。__new__() 的参数与按 py_fields`. The ``defaults 类属性中定义顺序的属性相对应的顺序一致,是一个将属性名称映射到其默认值的字典的类属性。

子类不应需要覆盖 __new__() 方法。它们可以为传递给 __new__() 的每个属性定义名为 _construct_<attr> 的类或静态方法,以处理传递给 Basic 的值。列在类属性 not_in_args 中的属性不会传递给。

kwargs(exclude=(), apply=None)

将实例的属性作为关键字参数的字典获取。

参数:

exclude : 字符串集合

要排除的关键字集合。

apply : 可调用对象,可选

应用于所有值的函数。

class sympy.codegen.ast.Type(*args, **kwargs)

表示类型。

参数:

name : 字符串

类型的名称,例如 objectint16float16(后两者将分别使用 Type 子类 IntTypeFloatType)。如果给定 Type 实例,则返回该实例。

解释

命名是 NumPy 命名的超集。Type 类具有类方法 from_expr,用于提供类型推导。它还具有 cast_check 方法,用于将参数强制转换为其类型,如果舍入误差不在容差范围内或者值无法由底层数据类型表示(例如无符号整数),可能会引发异常。

示例

>>> from sympy.codegen.ast import Type
>>> t = Type.from_expr(42)
>>> t
integer
>>> print(repr(t))
IntBaseType(String('integer'))
>>> from sympy.codegen.ast import uint8
>>> uint8.cast_check(-1)   
Traceback (most recent call last):
  ...
ValueError: Minimum value for data type bigger than new value.
>>> from sympy.codegen.ast import float32
>>> v6 = 0.123456
>>> float32.cast_check(v6)
0.123456
>>> v10 = 12345.67894
>>> float32.cast_check(v10)  
Traceback (most recent call last):
  ...
ValueError: Casting gives a significantly different value.
>>> boost_mp50 = Type('boost::multiprecision::cpp_dec_float_50')
>>> from sympy import cxxcode
>>> from sympy.codegen.ast import Declaration, Variable
>>> cxxcode(Declaration(Variable('x', type=boost_mp50)))
'boost::multiprecision::cpp_dec_float_50 x' 

引用

[R39]

numpy.org/doc/stable/user/basics.types.html

cast_check(value, rtol=None, atol=0, precision_targets=None)

将值转换为实例的数据类型。

参数:

value : 数字

rtol : 浮点数

相对容差。(如果未给出则将推导)

atol : 浮点数

绝对容差(除了 rtol)。

type_aliases : dict

用于类型映射的替换,例如 {integer: int64, real: float32}

示例

>>> from sympy.codegen.ast import integer, float32, int8
>>> integer.cast_check(3.0) == 3
True
>>> float32.cast_check(1e-40)  
Traceback (most recent call last):
  ...
ValueError: Minimum value for data type bigger than new value.
>>> int8.cast_check(256)  
Traceback (most recent call last):
  ...
ValueError: Maximum value for data type smaller than new value.
>>> v10 = 12345.67894
>>> float32.cast_check(v10)  
Traceback (most recent call last):
  ...
ValueError: Casting gives a significantly different value.
>>> from sympy.codegen.ast import float64
>>> float64.cast_check(v10)
12345.67894
>>> from sympy import Float
>>> v18 = Float('0.123456789012345646')
>>> float64.cast_check(v18)
Traceback (most recent call last):
  ...
ValueError: Casting gives a significantly different value.
>>> from sympy.codegen.ast import float80
>>> float80.cast_check(v18)
0.123456789012345649 
classmethod from_expr(expr)

从表达式或Symbol推断类型。

参数:

expr : 数字或 SymPy 对象

类型将从类型或属性推断。

引发:

类型推断失败时引发 ValueError。

示例

>>> from sympy.codegen.ast import Type, integer, complex_
>>> Type.from_expr(2) == integer
True
>>> from sympy import Symbol
>>> Type.from_expr(Symbol('z', complex=True)) == complex_
True
>>> Type.from_expr(sum)  
Traceback (most recent call last):
  ...
ValueError: Could not deduce type from expr. 
class sympy.codegen.ast.UnsignedIntType(*args, **kwargs)

表示一个无符号整数类型。

class sympy.codegen.ast.Variable(*args, **kwargs)

表示一个变量。

参数:

symbol : Symbol

type : Type(可选)

变量的类型。

attrs : 可迭代的 Attribute 实例

将被存储为元组。

示例

>>> from sympy import Symbol
>>> from sympy.codegen.ast import Variable, float32, integer
>>> x = Symbol('x')
>>> v = Variable(x, type=float32)
>>> v.attrs
()
>>> v == Variable('x')
False
>>> v == Variable('x', type=float32)
True
>>> v
Variable(x, type=float32) 

也可以通过对符号的假设推断出的类型使用deduced类方法构造Variable实例:

>>> i = Symbol('i', integer=True)
>>> v = Variable.deduced(i)
>>> v.type == integer
True
>>> v == Variable('i')
False
>>> from sympy.codegen.ast import value_const
>>> value_const in v.attrs
False
>>> w = Variable('w', attrs=[value_const])
>>> w
Variable(w, attrs=(value_const,))
>>> value_const in w.attrs
True
>>> w.as_Declaration(value=42)
Declaration(Variable(w, value=42, attrs=(value_const,))) 
as_Declaration(**kwargs)

创建 Declaration 实例的便利方法。

解释

如果声明的变量需要包装一个修改后的变量关键字参数(例如覆盖变量实例的value),可以传递。

示例

>>> from sympy.codegen.ast import Variable, NoneToken
>>> x = Variable('x')
>>> decl1 = x.as_Declaration()
>>> # value is special NoneToken() which must be tested with == operator
>>> decl1.variable.value is None  # won't work
False
>>> decl1.variable.value == None  # not PEP-8 compliant
True
>>> decl1.variable.value == NoneToken()  # OK
True
>>> decl2 = x.as_Declaration(value=42.0)
>>> decl2.variable.value == 42.0
True 
classmethod deduced(symbol, value=None, attrs=(), cast_check=True)

Type.from_expr推断类型的替代构造函数。

主要从symbol推断类型,次要从value推断。

参数:

symbol : Symbol

value : expr

(可选)变量的值。

attrs : 可迭代的 Attribute 实例

cast_check : bool

是否在value上应用Type.cast_check

示例

>>> from sympy import Symbol
>>> from sympy.codegen.ast import Variable, complex_
>>> n = Symbol('n', integer=True)
>>> str(Variable.deduced(n).type)
'integer'
>>> x = Symbol('x', real=True)
>>> v = Variable.deduced(x)
>>> v.type
real
>>> z = Symbol('z', complex=True)
>>> Variable.deduced(z).type == complex_
True 
class sympy.codegen.ast.While(*args, **kwargs)

表示代码中的‘for-loop’。

表达式的形式为:

“while condition:

body…”

参数:

condition : 可转换为布尔值的表达式

body : CodeBlock 或可迭代对象

当传递一个可迭代对象时,用于实例化CodeBlock

示例

>>> from sympy import symbols, Gt, Abs
>>> from sympy.codegen import aug_assign, Assignment, While
>>> x, dx = symbols('x dx')
>>> expr = 1 - x**2
>>> whl = While(Gt(Abs(dx), 1e-9), [
...     Assignment(dx, -expr/expr.diff(x)),
...     aug_assign(x, '+', dx)
... ]) 
sympy.codegen.ast.aug_assign(lhs, op, rhs)

创建‘lhs op= rhs’。

参数:

lhs : Expr

表示表达式左手边的 SymPy 对象。这些应该是单数对象,如编写代码时所用。显著的类型包括SymbolMatrixSymbolMatrixElementIndexed。支持这些类型的子类也被支持。

op : str

运算符(+、-、/、*、%)。

rhs : Expr

表示表达式右手边的 SymPy 对象。这可以是任何类型,只要其形状与左手边对应即可。例如,Matrix 类型可以分配给 MatrixSymbol,但不能分配给 Symbol,因为维度不会对齐。

解释

表示用于代码生成的增强变量赋值。这是一个便利函数。你也可以直接使用增强赋值类,比如AddAugmentedAssignment(x, y)

示例

>>> from sympy import symbols
>>> from sympy.codegen.ast import aug_assign
>>> x, y = symbols('x, y')
>>> aug_assign(x, '+', y)
AddAugmentedAssignment(x, y) 
```  ## 特殊的 C 数学函数(sympy.codegen.cfunctions)

此模块包含 SymPy 函数,与 C 标准库中的特殊数学函数相对应(自 C99 起,也可在 C++11 中使用)。

该模块中定义的函数允许用户将`expm1`之类的函数表达为 SymPy 函数,以进行符号操作。

```py
class sympy.codegen.cfunctions.Cbrt(*args)

表示立方根函数。

解释

选择Cbrt(x)而不是cbrt(x)的原因是后者在内部表示为Pow(x, Rational(1, 3)),这在进行代码生成时可能不是想要的结果。

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cfunctions import Cbrt
>>> Cbrt(x)
Cbrt(x)
>>> Cbrt(x).diff(x)
1/(3*x**(2/3)) 

另请参阅

Sqrt

fdiff(argindex=1)

返回此函数的一阶导数。

class sympy.codegen.cfunctions.Sqrt(*args)

表示平方根函数。

解释

为什么应该使用Sqrt(x)而不是sqrt(x)的原因是,后者在内部表示为Pow(x, S.Half),这可能不符合代码生成时的期望。

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cfunctions import Sqrt
>>> Sqrt(x)
Sqrt(x)
>>> Sqrt(x).diff(x)
1/(2*sqrt(x)) 

另请参见

Cbrt

fdiff(argindex=1)

返回此函数的一阶导数。

class sympy.codegen.cfunctions.exp2(arg)

代表以二为基数的指数函数。

解释

使用exp2(x)而不是2**x的好处在于,在有限精度算术下,后者效率不高。

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cfunctions import exp2
>>> exp2(2).evalf() == 4.0
True
>>> exp2(x).diff(x)
log(2)*exp2(x) 

另请参见

log2

fdiff(argindex=1)

返回此函数的一阶导数。

class sympy.codegen.cfunctions.expm1(arg)

代表以自然指数减一的指数函数。

解释

使用expm1(x)而不是exp(x) - 1的好处在于,后者在 x 接近零时容易出现取消精度问题。

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cfunctions import expm1
>>> '%.0e' % expm1(1e-99).evalf()
'1e-99'
>>> from math import exp
>>> exp(1e-99) - 1
0.0
>>> expm1(x).diff(x)
exp(x) 

另请参见

log1p

fdiff(argindex=1)

返回此函数的一阶导数。

class sympy.codegen.cfunctions.fma(*args)

代表“融合乘加”。

解释

使用fma(x, y, z)而不是x*y + z的好处在于,在有限精度算术下,前者受某些 CPU 的特殊指令支持。

示例

>>> from sympy.abc import x, y, z
>>> from sympy.codegen.cfunctions import fma
>>> fma(x, y, z).diff(x)
y 
fdiff(argindex=1)

返回此函数的一阶导数。

class sympy.codegen.cfunctions.hypot(*args)

代表求直角三角形斜边长度的函数。

解释

例如,在进行代码生成时,由 C99 标准的数学库提供直角三角形函数,因此可能希望在符号化表示函数时使用该函数。

示例

>>> from sympy.abc import x, y
>>> from sympy.codegen.cfunctions import hypot
>>> hypot(3, 4).evalf() == 5.0
True
>>> hypot(x, y)
hypot(x, y)
>>> hypot(x, y).diff(x)
x/hypot(x, y) 
fdiff(argindex=1)

返回此函数的一阶导数。

class sympy.codegen.cfunctions.log10(arg)

代表以十为底数的对数函数。

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cfunctions import log10
>>> log10(100).evalf() == 2.0
True
>>> log10(x).diff(x)
1/(x*log(10)) 

另请参见

log2

fdiff(argindex=1)

返回此函数的一阶导数。

class sympy.codegen.cfunctions.log1p(arg)

代表对数加一的自然对数。

解释

使用log1p(x)而不是log(x + 1)的好处在于,后者在 x 接近零时容易出现取消精度问题。

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cfunctions import log1p
>>> from sympy import expand_log
>>> '%.0e' % expand_log(log1p(1e-99)).evalf()
'1e-99'
>>> from math import log
>>> log(1 + 1e-99)
0.0
>>> log1p(x).diff(x)
1/(x + 1) 

另请参见

expm1

fdiff(argindex=1)

返回此函数的一阶导数。

class sympy.codegen.cfunctions.log2(arg)

代表以二为底数的对数函数。

解释

使用log2(x)而不是log(x)/log(2)的好处在于,在有限精度算术下,后者效率不高。

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cfunctions import log2
>>> log2(4).evalf() == 2.0
True
>>> log2(x).diff(x)
1/(x*log(2)) 

另请参见

exp2, log10

fdiff(argindex=1)

返回此函数的一阶导数。 ## C 特定 AST 节点(sympy.codegen.cnodes)

适用于 C 系语言特定的 AST 节点

class sympy.codegen.cnodes.CommaOperator(*args)

代表 C 语言中的逗号运算符

class sympy.codegen.cnodes.Label(*args, **kwargs)

用于例如 goto 语句的标签。

示例

>>> from sympy import ccode, Symbol
>>> from sympy.codegen.cnodes import Label, PreIncrement
>>> print(ccode(Label('foo')))
foo:
>>> print(ccode(Label('bar', [PreIncrement(Symbol('a'))])))
bar:
++(a); 
class sympy.codegen.cnodes.PostDecrement(*args)

代表后自减运算符

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cnodes import PostDecrement
>>> from sympy import ccode
>>> ccode(PostDecrement(x))
'(x)--' 
class sympy.codegen.cnodes.PostIncrement(*args)

代表后自增运算符

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cnodes import PostIncrement
>>> from sympy import ccode
>>> ccode(PostIncrement(x))
'(x)++' 
class sympy.codegen.cnodes.PreDecrement(*args)

代表前自减运算符

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cnodes import PreDecrement
>>> from sympy import ccode
>>> ccode(PreDecrement(x))
'--(x)' 
class sympy.codegen.cnodes.PreIncrement(*args)

代表前自增运算符

示例

>>> from sympy.abc import x
>>> from sympy.codegen.cnodes import PreIncrement
>>> from sympy import ccode
>>> ccode(PreIncrement(x))
'++(x)' 
sympy.codegen.cnodes.alignof(arg)

生成调用‘alignof’的 FunctionCall 实例

class sympy.codegen.cnodes.goto(*args, **kwargs)

代表 C 语言中的 goto

sympy.codegen.cnodes.sizeof(arg)

生成调用‘sizeof’的 FunctionCall 实例

示例

>>> from sympy.codegen.ast import real
>>> from sympy.codegen.cnodes import sizeof
>>> from sympy import ccode
>>> ccode(sizeof(real))
'sizeof(double)' 
class sympy.codegen.cnodes.struct(*args, **kwargs)

表示 C 中的结构

class sympy.codegen.cnodes.union(*args, **kwargs)

表示 C 中的联合 ## C++特定的 AST 节点(sympy.codegen.cxxnodes)

专用于 C++的 AST 节点。

class sympy.codegen.cxxnodes.using(*args, **kwargs)

表示 C++中的‘using’语句 ## Fortran 特定的 AST 节点(sympy.codegen.fnodes)

专用于 Fortran 的 AST 节点。

该模块中定义的函数允许用户将诸如dsign之类的函数表达为 SymPy 函数以进行符号操作。

class sympy.codegen.fnodes.ArrayConstructor(*args, **kwargs)

表示一个数组构造器。

示例

>>> from sympy import fcode
>>> from sympy.codegen.fnodes import ArrayConstructor
>>> ac = ArrayConstructor([1, 2, 3])
>>> fcode(ac, standard=95, source_format='free')
'(/1, 2, 3/)'
>>> fcode(ac, standard=2003, source_format='free')
'[1, 2, 3]' 
class sympy.codegen.fnodes.Do(*args, **kwargs)

表示 Fortran 中的 Do 循环。

示例

>>> from sympy import fcode, symbols
>>> from sympy.codegen.ast import aug_assign, Print
>>> from sympy.codegen.fnodes import Do
>>> i, n = symbols('i n', integer=True)
>>> r = symbols('r', real=True)
>>> body = [aug_assign(r, '+', 1/i), Print([i, r])]
>>> do1 = Do(body, i, 1, n)
>>> print(fcode(do1, source_format='free'))
do i = 1, n
 r = r + 1d0/i
 print *, i, r
end do
>>> do2 = Do(body, i, 1, n, 2)
>>> print(fcode(do2, source_format='free'))
do i = 1, n, 2
 r = r + 1d0/i
 print *, i, r
end do 
class sympy.codegen.fnodes.Extent(*args)

表示一个维度范围。

示例

>>> from sympy.codegen.fnodes import Extent
>>> e = Extent(-3, 3)  # -3, -2, -1, 0, 1, 2, 3
>>> from sympy import fcode
>>> fcode(e, source_format='free')
'-3:3'
>>> from sympy.codegen.ast import Variable, real
>>> from sympy.codegen.fnodes import dimension, intent_out
>>> dim = dimension(e, e)
>>> arr = Variable('x', real, attrs=[dim, intent_out])
>>> fcode(arr.as_Declaration(), source_format='free', standard=2003)
'real*8, dimension(-3:3, -3:3), intent(out) :: x' 
class sympy.codegen.fnodes.FortranReturn(*args, **kwargs)

明确映射到 Fortran“return”的 AST 节点。

说明

因为 Fortran 中的返回语句与 C 中的不同,并且为了帮助重用我们的代码生成 AST,普通的.codegen.ast.Return被解释为对函数的结果变量的赋值。如果由于某种原因需要生成一个 Fortran RETURN 语句,应使用此节点。

示例

>>> from sympy.codegen.fnodes import FortranReturn
>>> from sympy import fcode
>>> fcode(FortranReturn('x'))
'       return x' 
class sympy.codegen.fnodes.GoTo(*args, **kwargs)

表示 Fortran 中的 goto 语句

示例

>>> from sympy.codegen.fnodes import GoTo
>>> go = GoTo([10, 20, 30], 'i')
>>> from sympy import fcode
>>> fcode(go, source_format='free')
'go to (10, 20, 30), i' 
class sympy.codegen.fnodes.ImpliedDoLoop(*args, **kwargs)

表示 Fortran 中的隐含 do 循环。

示例

>>> from sympy import Symbol, fcode
>>> from sympy.codegen.fnodes import ImpliedDoLoop, ArrayConstructor
>>> i = Symbol('i', integer=True)
>>> idl = ImpliedDoLoop(i**3, i, -3, 3, 2)  # -27, -1, 1, 27
>>> ac = ArrayConstructor([-28, idl, 28]) # -28, -27, -1, 1, 27, 28
>>> fcode(ac, standard=2003, source_format='free')
'[-28, (i**3, i = -3, 3, 2), 28]' 
class sympy.codegen.fnodes.Module(*args, **kwargs)

表示 Fortran 中的模块。

示例

>>> from sympy.codegen.fnodes import Module
>>> from sympy import fcode
>>> print(fcode(Module('signallib', ['implicit none'], []), source_format='free'))
module signallib
implicit none

contains

end module 
class sympy.codegen.fnodes.Program(*args, **kwargs)

表示 Fortran 中的‘program’块。

示例

>>> from sympy.codegen.ast import Print
>>> from sympy.codegen.fnodes import Program
>>> prog = Program('myprogram', [Print([42])])
>>> from sympy import fcode
>>> print(fcode(prog, source_format='free'))
program myprogram
 print *, 42
end program 
class sympy.codegen.fnodes.Subroutine(*args, **kwargs)

表示 Fortran 中的子程序。

示例

>>> from sympy import fcode, symbols
>>> from sympy.codegen.ast import Print
>>> from sympy.codegen.fnodes import Subroutine
>>> x, y = symbols('x y', real=True)
>>> sub = Subroutine('mysub', [x, y], [Print([x**2 + y**2, x*y])])
>>> print(fcode(sub, source_format='free', standard=2003))
subroutine mysub(x, y)
real*8 :: x
real*8 :: y
print *, x**2 + y**2, x*y
end subroutine 
class sympy.codegen.fnodes.SubroutineCall(*args, **kwargs)

表示 Fortran 中的子程序调用。

示例

>>> from sympy.codegen.fnodes import SubroutineCall
>>> from sympy import fcode
>>> fcode(SubroutineCall('mysub', 'x y'.split()))
'       call mysub(x, y)' 
sympy.codegen.fnodes.allocated(array)

为 Fortran 的“allocated(…)”创建一个函数调用的 AST 节点。

示例

>>> from sympy import fcode
>>> from sympy.codegen.fnodes import allocated
>>> alloc = allocated('x')
>>> fcode(alloc, source_format='free')
'allocated(x)' 
sympy.codegen.fnodes.array(symbol, dim, intent=None, *, attrs=(), value=None, type=None)

用于为 Fortran 数组创建一个变量实例的便利函数。

参数:

symbol:符号

dim:属性或可迭代对象

如果 dim 是一个Attribute,它需要具有名称‘dimension’。如果它不是一个Attribute,那么它将作为*dim传递给dimension()

intent:str

其中之一:‘in’、‘out’、‘inout’或无

**kwargs:

Variable的关键字参数(‘type’和‘value’)

示例

>>> from sympy import fcode
>>> from sympy.codegen.ast import integer, real
>>> from sympy.codegen.fnodes import array
>>> arr = array('a', '*', 'in', type=integer)
>>> print(fcode(arr.as_Declaration(), source_format='free', standard=2003))
integer*4, dimension(*), intent(in) :: a
>>> x = array('x', [3, ':', ':'], intent='out', type=real)
>>> print(fcode(x.as_Declaration(value=1), source_format='free', standard=2003))
real*8, dimension(3, :, :), intent(out) :: x = 1 
sympy.codegen.fnodes.bind_C(name=None)

创建一个带有名称的属性bind_C

参数:

name:str

示例

>>> from sympy import fcode, Symbol
>>> from sympy.codegen.ast import FunctionDefinition, real, Return
>>> from sympy.codegen.fnodes import array, sum_, bind_C
>>> a = Symbol('a', real=True)
>>> s = Symbol('s', integer=True)
>>> arr = array(a, dim=[s], intent='in')
>>> body = [Return((sum_(a**2)/s)**.5)]
>>> fd = FunctionDefinition(real, 'rms', [arr, s], body, attrs=[bind_C('rms')])
>>> print(fcode(fd, source_format='free', standard=2003))
real*8 function rms(a, s) bind(C, name="rms")
real*8, dimension(s), intent(in) :: a
integer*4 :: s
rms = sqrt(sum(a**2)/s)
end function 
class sympy.codegen.fnodes.cmplx(*args)

Fortran 复数转换函数。

sympy.codegen.fnodes.dimension(*args)

创建一个带有(最多 7 个)范围的‘dimension’属性。

示例

>>> from sympy import fcode
>>> from sympy.codegen.fnodes import dimension, intent_in
>>> dim = dimension('2', ':')  # 2 rows, runtime determined number of columns
>>> from sympy.codegen.ast import Variable, integer
>>> arr = Variable('a', integer, attrs=[dim, intent_in])
>>> fcode(arr.as_Declaration(), source_format='free', standard=2003)
'integer*4, dimension(2, :), intent(in) :: a' 
class sympy.codegen.fnodes.dsign(*args)

用于双精度参数的 Fortran 符号内置函数。

class sympy.codegen.fnodes.isign(*args)

用于整数参数的 Fortran 符号内置函数。

class sympy.codegen.fnodes.kind(*args)

Fortran kind 函数。

sympy.codegen.fnodes.lbound(array, dim=None, kind=None)

为 Fortran 的“lbound(…)”创建一个函数调用的 AST 节点。

参数:

array:符号或字符串

dim:表达式

kind:表达式

示例

>>> from sympy import fcode
>>> from sympy.codegen.fnodes import lbound
>>> lb = lbound('arr', dim=2)
>>> fcode(lb, source_format='free')
'lbound(arr, 2)' 
class sympy.codegen.fnodes.literal_dp(num, dps=None, precision=None)

Fortran 双精度实数字面量

class sympy.codegen.fnodes.literal_sp(num, dps=None, precision=None)

Fortran 单精度实数字面量

class sympy.codegen.fnodes.merge(*args)

Fortran 合并函数

sympy.codegen.fnodes.reshape(source, shape, pad=None, order=None)

为 Fortran 的“reshape(…)”创建一个函数调用的 AST 节点。

参数:

source:符号或字符串

shape:ArrayExpr

sympy.codegen.fnodes.shape(source, kind=None)

为 Fortran 的“shape(…)”创建一个函数调用的 AST 节点。

参数:

source:符号或字符串

kind:表达式

示例

>>> from sympy import fcode
>>> from sympy.codegen.fnodes import shape
>>> shp = shape('x')
>>> fcode(shp, source_format='free')
'shape(x)' 
sympy.codegen.fnodes.size(array, dim=None, kind=None)

为 Fortran 的“size(…)”创建一个函数调用的 AST 节点。

示例

>>> from sympy import fcode, Symbol
>>> from sympy.codegen.ast import FunctionDefinition, real, Return
>>> from sympy.codegen.fnodes import array, sum_, size
>>> a = Symbol('a', real=True)
>>> body = [Return((sum_(a**2)/size(a))**.5)]
>>> arr = array(a, dim=[':'], intent='in')
>>> fd = FunctionDefinition(real, 'rms', [arr], body)
>>> print(fcode(fd, source_format='free', standard=2003))
real*8 function rms(a)
real*8, dimension(:), intent(in) :: a
rms = sqrt(sum(a**2)*1d0/size(a))
end function 
class sympy.codegen.fnodes.use(*args, **kwargs)

表示 Fortran 中的 use 语句。

示例

>>> from sympy.codegen.fnodes import use
>>> from sympy import fcode
>>> fcode(use('signallib'), source_format='free')
'use signallib'
>>> fcode(use('signallib', [('metric', 'snr')]), source_format='free')
'use signallib, metric => snr'
>>> fcode(use('signallib', only=['snr', 'convolution2d']), source_format='free')
'use signallib, only: snr, convolution2d' 
class sympy.codegen.fnodes.use_rename(*args, **kwargs)

表示 Fortran 中 use 语句中的重命名。

示例

>>> from sympy.codegen.fnodes import use_rename, use
>>> from sympy import fcode
>>> ren = use_rename("thingy", "convolution2d")
>>> print(fcode(ren, source_format='free'))
thingy => convolution2d
>>> full = use('signallib', only=['snr', ren])
>>> print(fcode(full, source_format='free'))
use signallib, only: snr, thingy => convolution2d 
```  ## 算法(sympy.codegen.algorithms)

```py
sympy.codegen.algorithms.newtons_method(expr, wrt, atol=1e-12, delta=None, *, rtol=4e-16, debug=False, itermax=None, counter=None, delta_fn=<function <lambda>>, cse=False, handle_nan=None, bounds=None)

为 Newton-Raphson 方法(一种寻根算法)生成 AST。

参数:

expr:表达式

wrt:符号

关于,即变量是什么。

atol:数字或表达式

绝对容差(停止准则)

rtol : 数字或表达式

相对容差(停止准则)

delta : 符号

如果为 None,将是一个 Dummy

debug : 布尔值

是否在迭代过程中打印收敛信息

itermax : 数字或表达式

迭代的最大次数。

counter : 符号

如果为 None,将是一个 Dummy

delta_fn: Callable[[Expr, Symbol], Expr]

计算步骤,默认为牛顿法。例如,对于 Halley 方法,使用 delta_fn=lambda e, x: -2*e*e.diff(x)/(2*e.diff(x)**2 - e*e.diff(x, 2))

cse: 布尔值

delta 表达式上执行常见子表达式消除

handle_nan: 令牌

如何处理非数值(NaN)的出现。

bounds: Optional[tuple[Expr, Expr]]

在界限内执行优化

解释

基于 sympy.codegen.ast 生成的牛顿法根查找的抽象语法树(AST)。

示例

>>> from sympy import symbols, cos
>>> from sympy.codegen.ast import Assignment
>>> from sympy.codegen.algorithms import newtons_method
>>> x, dx, atol = symbols('x dx atol')
>>> expr = cos(x) - x**3
>>> algo = newtons_method(expr, x, atol=atol, delta=dx)
>>> algo.has(Assignment(dx, -expr/expr.diff(x)))
True 

参考

[R40]

en.wikipedia.org/wiki/Newton%27s_method

sympy.codegen.algorithms.newtons_method_function(expr, wrt, params=None, func_name='newton', attrs=(), *, delta=None, **kwargs)

生成实现牛顿-拉弗森方法的函数的 AST。

参数:

expr : 表达式

wrt : 符号

关于,即是变量是什么

params : 符号的可迭代对象

在表达式中出现且在迭代过程中被视为常数的符号(这些将被接受为生成函数的参数)。

func_name : 字符串

生成函数的名称。

attrs : 元组

传递给 FunctionDefinitionattrs 属性实例。

**kwargs :

传递给 sympy.codegen.algorithms.newtons_method() 的关键字参数。

示例

>>> from sympy import symbols, cos
>>> from sympy.codegen.algorithms import newtons_method_function
>>> from sympy.codegen.pyutils import render_as_module
>>> x = symbols('x')
>>> expr = cos(x) - x**3
>>> func = newtons_method_function(expr, x)
>>> py_mod = render_as_module(func)  # source code as string
>>> namespace = {}
>>> exec(py_mod, namespace, namespace)
>>> res = eval('newton(0.5)', namespace)
>>> abs(res - 0.865474033102) < 1e-12
True 

参见

sympy.codegen.algorithms.newtons_method ## Python 实用工具(sympy.codegen.pyutils)

sympy.codegen.pyutils.render_as_module(content, standard='python3')

将 Python 代码呈现为模块(带有必要的导入)。

参数:

standard :

查看 sympy.printing.pycode.pycode() 中的参数standard ## C 实用工具(sympy.codegen.cutils)

sympy.codegen.cutils.render_as_source_file(content, Printer=<class 'sympy.printing.c.C99CodePrinter'>, settings=None)

渲染为 C 源文件(带有必要的 #include 语句) ## Fortran 实用工具(sympy.codegen.futils)

sympy.codegen.futils.render_as_module(definitions, name, declarations=(), printer_settings=None)

创建 Module 实例并将其呈现为字符串。

这将生成带有正确 use 语句的 Fortran 源代码模块。

参数:

definitions : 可迭代对象

传递给 sympy.codegen.fnodes.Module

name : 字符串

传递给 sympy.codegen.fnodes.Module

declarations : 可迭代对象

传递给 sympy.codegen.fnodes.Module。它将通过 definitions 生成 use 语句、‘implicit none’ 和 public 列表扩展。

printer_settings : 字典

传递给 FCodePrinter(默认:{'standard': 2003, 'source_format': 'free'})。