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
](https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general))
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
](https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general))
快速 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_fwht
或 convolution_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
](https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general))
使用數論變換執行卷積
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
](https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general))
使用快速沃爾什-哈達瑪變換執行子集卷積。
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 位小數。您可以選擇將所需的精度(應為正整數)作為引數傳遞給 evalf
或 N
:
>>> 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
,最好傳遞字串、Rational
或 evalf
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
因此,顯示的精度不應用作錯誤傳播或重要性算術的模型;相反,該方案用於確保數值演算法的穩定性。
N
和 evalf
可用於更改現有浮點數的精度:
>>> N(3.5)
3.50000000000000
>>> N(3.5, 5)
3.5000
>>> N(3.5, 30)
3.50000000000000000000000000000
精度和錯誤處理
當輸入到 N
或 evalf
的是複雜表示式時,數值誤差傳播成為一個問題。例如,考慮第 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
N
和 evalf
會跟蹤錯誤並自動增加內部使用的精度,以獲得正確的結果:
>>> 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
可以透過告知 evalf
或 N
使用振盪積分演算法來更有效地處理它:
>>> 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/evalf
和lambdify
更快。
所有上述內容的 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/evalf | 50us | 簡單 | None |
lambdify | 1us | 標量函式 | math |
lambdify-numpy | 10ns | 向量函式 | numpy |
ufuncify | 10ns | 複雜向量表示式 | f2py, Cython |
lambdify-cupy | 10ns | GPU 上的向量函式 | cupy |
lambdify-jax | 10ns | CPU、GPU 和 TPU 上的向量函式 | jax |
Aesara | 10ns | 多輸出,CSE,GPU | Aesara |
項重寫
原文連結:
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 更低階,因為它實際上不嘗試編譯程式碼,但比印表機更高階,因為它生成可編譯的檔案(包括標頭檔案),而不僅僅是程式碼片段。
在這裡友好的函式是codegen
和make_routine
。codegen
接受(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
是一個不區分大小寫的字串,表示原始碼語言。目前支援C
、F95
和Octave
。Octave
生成與 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 物件,如Routine
和Variable
並非 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 自動生成程式碼,將其寫入磁碟,編譯它並匯入到當前會話中。本模組的主要功能是autowrap
,binary_function
和ufuncify
。
它還會自動將包含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 不會使命令列後端靜音。這對除錯非常有幫助。
引數language
和backend
用於將預設值從Fortran
和f2py
更改為C
和Cython
。引數 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];
}
這略微不夠最佳化,因為
-
我們分配了額外的
temp
陣列 -
當一次就足夠時,我們對
x
記憶體進行了兩次遍歷
更好的解決方案將兩個逐元素操作融合為單個迴圈
for(int i = i; i < n; i++)
{
y[i] = sin(x[i]) / x[i];
}
像 NumPy 這樣的靜態編譯專案無法利用這些最佳化。幸運的是,SymPy 能夠生成高效的低階別 C 或 Fortran 程式碼。然後,它可以依賴於像 Cython
或 f2py
這樣的專案來編譯並重新連線該程式碼回到 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
例項供方便使用。也許最常見的兩種用於程式碼生成(數值程式碼)的是float32
和float64
(分別稱為單精度和雙精度)。此外,還有精確的通用型別版本(在列印時選擇底層資料型別):real
、integer
、complex_
、bool_
。
其他定義的Type
例項為:
-
intc
:C 中使用的整數型別。 -
intp
:C 中使用的無符號整數型別。 -
int8
、int16
、int32
、int64
:n 位整數。 -
uint8
、uint16
、uint32
、uint64
: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 例項 stdout
和 stderr
。
引數:
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 : 字串
型別的名稱,例如
object
,int16
,float16
(後兩者將分別使用Type
子類IntType
和FloatType
)。如果給定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
用於型別對映的替換,例如
示例
>>> 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 物件。這些應該是單數物件,如編寫程式碼時所用。顯著的型別包括
Symbol
、MatrixSymbol
、MatrixElement
和Indexed
。支援這些型別的子類也被支援。
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 : 元組
傳遞給
FunctionDefinition
的attrs
屬性例項。
**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'}
)。
邏輯
原文:
docs.sympy.org/latest/reference/public/logic/index.html
目錄
-
邏輯
-
集合
邏輯
原文連結:
docs.sympy.org/latest/modules/logic.html
介紹
SymPy 的邏輯模組允許使用符號和布林值形成和操作邏輯表示式。
形成邏輯表示式
您可以使用標準的 Python 運算子&
(And
)、|
(Or
)、~
(Not
)構建布林表示式:
>>> from sympy import *
>>> x, y = symbols('x,y')
>>> y | (x & y)
y | (x & y)
>>> x | y
x | y
>>> ~x
~x
您還可以使用>>
和<<
形成含義:
>>> x >> y
Implies(x, y)
>>> x << y
Implies(y, x)
像 SymPy 中的大多數型別一樣,布林表示式繼承自 Basic
:
>>> (y & x).subs({x: True, y: True})
True
>>> (x | y).atoms()
{x, y}
SymPy 的邏輯模組還包括以下功能,可從其真值表中推導布林表示式:
sympy.logic.boolalg.SOPform(variables, minterms, dontcares=None)
函式SOPform
使用簡化對和冗餘組消除演算法將產生‘1’的所有輸入組合列表(即最小項)轉換為最小的“求和乘積”形式。
變數必須作為第一個引數給出。
返回邏輯 Or
函式(即“求和乘積”或“SOP”形式),以達到所需的結果。如果有可以忽略的輸入,請也將它們作為列表傳遞。
結果將是滿足條件的函式之一(也許有多個)。
示例
>>> from sympy.logic import SOPform
>>> from sympy import symbols
>>> w, x, y, z = symbols('w x y z')
>>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1],
... [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]]
>>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]]
>>> SOPform([w, x, y, z], minterms, dontcares)
(y & z) | (~w & ~x)
術語也可以表示為整數:
>>> minterms = [1, 3, 7, 11, 15]
>>> dontcares = [0, 2, 5]
>>> SOPform([w, x, y, z], minterms, dontcares)
(y & z) | (~w & ~x)
它們還可以使用字典來指定,不必完全指定:
>>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}]
>>> SOPform([w, x, y, z], minterms)
(x & ~w) | (y & z & ~x)
或其組合:
>>> minterms = [4, 7, 11, [1, 1, 1, 1]]
>>> dontcares = [{w : 0, x : 0, y: 0}, 5]
>>> SOPform([w, x, y, z], minterms, dontcares)
(w & y & z) | (~w & ~y) | (x & z & ~w)
參見
POSform
參考文獻
[R600]
zh.wikipedia.org/wiki/奎因-麥克拉斯基演算法
[R601]
zh.wikipedia.org/wiki/無關緊要的術語
sympy.logic.boolalg.POSform(variables, minterms, dontcares=None)
函式POSform
使用簡化對和冗餘組消除演算法將產生‘1’的所有輸入組合列表(即最小項)轉換為最小的“乘積求和”形式。
變數必須作為第一個引數給出。
返回邏輯 And
函式(即“乘積求和”或“POS”形式),以達到所需的結果。如果有可以忽略的輸入,請也將它們作為列表傳遞。
結果將是滿足條件的函式之一(也許有多個)。
示例
>>> from sympy.logic import POSform
>>> from sympy import symbols
>>> w, x, y, z = symbols('w x y z')
>>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1],
... [1, 0, 1, 1], [1, 1, 1, 1]]
>>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]]
>>> POSform([w, x, y, z], minterms, dontcares)
z & (y | ~w)
術語也可以表示為整數:
>>> minterms = [1, 3, 7, 11, 15]
>>> dontcares = [0, 2, 5]
>>> POSform([w, x, y, z], minterms, dontcares)
z & (y | ~w)
它們還可以使用字典來指定,不必完全指定:
>>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}]
>>> POSform([w, x, y, z], minterms)
(x | y) & (x | z) & (~w | ~x)
或其組合:
>>> minterms = [4, 7, 11, [1, 1, 1, 1]]
>>> dontcares = [{w : 0, x : 0, y: 0}, 5]
>>> POSform([w, x, y, z], minterms, dontcares)
(w | x) & (y | ~w) & (z | ~y)
參見
SOPform
參考文獻
[R602]
zh.wikipedia.org/wiki/奎因-麥克拉斯基演算法
[R603]
zh.wikipedia.org/wiki/無關緊要的術語
sympy.logic.boolalg.ANFform(variables, truthvalues)
ANFform 函式將真值列表轉換為代數正常形式(ANF)。
變數必須作為第一個引數給出。
返回True
、False
、邏輯And
函式(即“Zhegalkin 單項式”)或邏輯Xor
函式(即“Zhegalkin 多項式”)。當 True 和 False 分別由 1 和 0 表示時,And
為乘法,Xor
為加法。
嚴格來說,“Zhegalkin 單項式”是一組不同變數(包括空集)的乘積(邏輯 And),其乘積表示為 1(True)。“Zhegalkin 多項式”是 Zhegalkin 單項式集合的和(邏輯 Xor),其中空集表示為 0(False)。
引數:
變數:變數列表
真值:1 和 0 的列表(真值表的結果列)
示例
>>> from sympy.logic.boolalg import ANFform
>>> from sympy.abc import x, y
>>> ANFform([x], [1, 0])
x ^ True
>>> ANFform([x, y], [0, 1, 1, 1])
x ^ y ^ (x & y)
參考文獻
[R604]
zh.wikipedia.org/wiki/Zhegalkin_polynomial
布林函式
class sympy.logic.boolalg.Boolean(*args)
布林物件是一種邏輯操作有意義的物件。
as_set()
用實集的術語重寫布林表示式。
示例
>>> from sympy import Symbol, Eq, Or, And
>>> x = Symbol('x', real=True)
>>> Eq(x, 0).as_set()
{0}
>>> (x > 0).as_set()
Interval.open(0, oo)
>>> And(-2 < x, x < 2).as_set()
Interval.open(-2, 2)
>>> Or(x < -2, 2 < x).as_set()
Union(Interval.open(-oo, -2), Interval.open(2, oo))
equals(other)
如果給定的公式具有相同的真值表,則返回True
。要使兩個公式相等,它們必須具有相同的文字。
示例
>>> from sympy.abc import A, B, C
>>> from sympy import And, Or, Not
>>> (A >> B).equals(~B >> ~A)
True
>>> Not(And(A, B, C)).equals(And(Not(A), Not(B), Not(C)))
False
>>> Not(And(A, Not(A))).equals(Or(B, Not(B)))
False
class sympy.logic.boolalg.BooleanTrue
SymPy 版本的True
,可以透過S.true
訪問的單例。
這是邏輯模組中使用的 SymPy 版本的True
。使用true
而不是True
的主要優勢在於,像~
和>>
這樣的簡寫布林操作在這個類上將按預期工作,而在True
上則按位操作 1。在邏輯模組中,當函式求值為 true 時,它們將返回這個類。
注意
在 SymPy 的各種上下文中,關於何時使用True
和何時使用S.true
可能會有些混淆。重要的是要記住,sympify(True)
返回S.true
。這意味著在大多數情況下,您可以直接使用True
,必要時它會自動轉換為S.true
,類似於您通常可以使用 1 代替S.One
。
基本原則是:
“如果所討論的布林值可以被任意符號的Boolean
替換,如Or(x, y)
或x > 1
,則使用S.true
。否則,使用True
”
換句話說,僅在布林用作真實符號表示的情況下使用S.true
。例如,如果物件最終位於任何表示式的.args
中,則必須是S.true
而不是True
,因為.args
的元素必須是Basic
。另一方面,==
在 SymPy 中不是一個符號操作,因為它總是以結構相等性返回True
或False
,而不是數學上的相等性,因此應該返回True
。假設系統應使用True
和False
。除了不滿足上述經驗法則外,假設系統使用三值邏輯(True
,False
,None
),而S.true
和S.false
表示二值邏輯。當有疑問時,使用True
。
“S.true == True is True
.”
雖然“S.true is True
”是False
,但“S.true == True
”是True
,因此,如果對於函式或表示式是否會返回S.true
或True
存在任何疑問,只需使用==
而不是is
來進行比較,它將在任何情況下都起作用。最後,對於布林標誌,最好只是使用if x
而不是if x is True
。引用 PEP 8:
不要使用==
將布林值與True
或False
進行比較。
-
是的:
if greeting:
-
不:
if greeting == True:
-
更糟糕的是:
if greeting is True:
舉例
>>> from sympy import sympify, true, false, Or
>>> sympify(True)
True
>>> _ is True, _ is true
(False, True)
>>> Or(true, false)
True
>>> _ is true
True
Python 運算子對 true 給出布林結果,但對 True 給出位結果
>>> ~true, ~True
(False, -2)
>>> true >> true, True >> True
(True, 0)
另請參閱
sympy.logic.boolalg.BooleanFalse
as_set()
重寫邏輯運算子和關係運算子以真實集合的術語表示。
舉例
>>> from sympy import true
>>> true.as_set()
UniversalSet
class sympy.logic.boolalg.BooleanFalse
SymPy 版本的False
,可以透過S.false
訪問的單例。
這是 SymPy 版本的False
,用於邏輯模組中。使用false
而不是False
的主要優勢在於,像~
和>>
這樣的簡便布林運算子會按預期在這個類上起作用,而對於False
,它們會按位操作 0。在邏輯模組中,當它們評估為 false 時,函式將返回此類。
註釋
在sympy.logic.boolalg.BooleanTrue
的註釋部分檢視筆記
舉例
>>> from sympy import sympify, true, false, Or
>>> sympify(False)
False
>>> _ is False, _ is false
(False, True)
>>> Or(true, false)
True
>>> _ is true
True
Python 運算子對 false 給出布林結果,但對 False 給出位結果
>>> ~false, ~False
(True, -1)
>>> false >> false, False >> False
(True, 0)
另請參閱
sympy.logic.boolalg.BooleanTrue
as_set()
重寫邏輯運算子和關係運算子以真實集合的術語表示。
舉例
>>> from sympy import false
>>> false.as_set()
EmptySet
class sympy.logic.boolalg.And(*args)
邏輯與功能。
當一個引數為 false 時,按順序評估其引數,如果它們都為 true,則立即返回 false。
舉例
>>> from sympy.abc import x, y
>>> from sympy import And
>>> x & y
x & y
註釋
邏輯與運算子&
作為便利性提供,但請注意其在這裡的使用與 Python 中的正常用法不同,即它是位與。因此,And(a, b)
和a & b
將在a
和b
為整數時產生不同的結果。
>>> And(x, y).subs(x, 1)
y
class sympy.logic.boolalg.Or(*args)
邏輯或函式
按順序評估其引數,如果一個引數為真,則立即返回 true,如果它們都為 false,則返回 false。
舉例
>>> from sympy.abc import x, y
>>> from sympy import Or
>>> x | y
x | y
註釋
|
運算子是為了方便起見提供的,但請注意,它在這裡的使用與 Python 中的正常用法不同,Python 中它表示按位或。因此,如果 a
和 b
是整數,Or(a, b)
和 a | b
將返回不同的結果。
>>> Or(x, y).subs(x, 0)
y
class sympy.logic.boolalg.Not(arg)
邏輯 Not 函式(否定)
如果語句為 false
或 False
,則返回 true
;如果語句為 true
或 True
,則返回 false
。
示例
>>> from sympy import Not, And, Or
>>> from sympy.abc import x, A, B
>>> Not(True)
False
>>> Not(False)
True
>>> Not(And(True, False))
True
>>> Not(Or(True, False))
False
>>> Not(And(And(True, x), Or(x, False)))
~x
>>> ~x
~x
>>> Not(And(Or(A, B), Or(~A, ~B)))
~((A | B) & (~A | ~B))
注意
-
~
運算子是為了方便起見提供的,但請注意,它在這裡的使用與 Python 中的正常用法不同,Python 中它表示按位取反。特別地,~a
和Not(a)
如果a
是整數將不同。此外,由於 Python 中的布林值是從int
繼承而來,~True
將與~1
相同,即-2
,其布林值為 True。為避免此問題,請使用 SymPy 的布林型別true
和false
。 -
在 Python 3.12 中,對 Python 的布林型別使用位取反運算子
~
已經不推薦使用,並將會發出警告。
>>> from sympy import true
>>> ~True
-2
>>> ~true
False
class sympy.logic.boolalg.Xor(*args)
邏輯 XOR(異或)函式。
如果奇數個引數為 True 而其餘為 False,則返回 True。
如果偶數個引數為 True 而其餘為 False,則返回 False。
示例
>>> from sympy.logic.boolalg import Xor
>>> from sympy import symbols
>>> x, y = symbols('x y')
>>> Xor(True, False)
True
>>> Xor(True, True)
False
>>> Xor(True, False, True, True, False)
True
>>> Xor(True, False, True, False)
False
>>> x ^ y
x ^ y
注意
^
運算子是為了方便起見提供的,但請注意,它在這裡的使用與 Python 中的正常用法不同,Python 中它表示按位異或。特別地,a ^ b
和 Xor(a, b)
如果 a
和 b
是整數將不同。
>>> Xor(x, y).subs(y, 0)
x
class sympy.logic.boolalg.Nand(*args)
邏輯 NAND 函式。
它按順序評估其引數,如果任何引數為 False,則立即返回 True;如果它們全部為 True,則返回 False。
如果任何引數為 False,則返回 True;如果所有引數為 True,則返回 False。
示例
>>> from sympy.logic.boolalg import Nand
>>> from sympy import symbols
>>> x, y = symbols('x y')
>>> Nand(False, True)
True
>>> Nand(True, True)
False
>>> Nand(x, y)
~(x & y)
class sympy.logic.boolalg.Nor(*args)
邏輯 NOR 函式。
它按順序評估其引數,如果任何引數為 True,則立即返回 False;如果它們全部為 False,則返回 True。
如果任何引數為 True,則返回 False;如果所有引數為 False,則返回 True。
示例
>>> from sympy.logic.boolalg import Nor
>>> from sympy import symbols
>>> x, y = symbols('x y')
>>> Nor(True, False)
False
>>> Nor(True, True)
False
>>> Nor(False, True)
False
>>> Nor(False, False)
True
>>> Nor(x, y)
~(x | y)
class sympy.logic.boolalg.Xnor(*args)
邏輯 XNOR 函式。
如果奇數個引數為 True 而其餘為 False,則返回 False。
如果偶數個引數為 True 而其餘為 False,則返回 True。
示例
>>> from sympy.logic.boolalg import Xnor
>>> from sympy import symbols
>>> x, y = symbols('x y')
>>> Xnor(True, False)
False
>>> Xnor(True, True)
True
>>> Xnor(True, False, True, True, False)
False
>>> Xnor(True, False, True, False)
True
class sympy.logic.boolalg.Implies(*args)
邏輯蘊含。
A 蘊含 B 相當於如果 A 則 B。在數學上,它寫作 (A \Rightarrow B),相當於 (\neg A \vee B) 或 ~A | B
。
接受兩個布林引數;A 和 B。如果 A 為 True 而 B 為 False,則返回 False;否則返回 True。
示例
>>> from sympy.logic.boolalg import Implies
>>> from sympy import symbols
>>> x, y = symbols('x y')
>>> Implies(True, False)
False
>>> Implies(False, False)
True
>>> Implies(True, True)
True
>>> Implies(False, True)
True
>>> x >> y
Implies(x, y)
>>> y << x
Implies(x, y)
注意
>>
和 <<
運算子是為了方便起見提供的,但請注意,它們在這裡的使用與 Python 中的正常用法不同,Python 中它們表示位移。因此,如果 a
和 b
是整數,Implies(a, b)
和 a >> b
將返回不同的結果。特別地,因為 Python 認為 True
和 False
是整數,True >> True
將與 1 >> 1
相同,即 0,其布林值為 False。為避免此問題,請使用 SymPy 物件 true
和 false
。
>>> from sympy import true, false
>>> True >> False
1
>>> true >> false
False
class sympy.logic.boolalg.Equivalent(*args)
等價關係。
Equivalent(A, B)
當且僅當 A 和 B 都為 True 或都為 False 時為 True。
如果所有引數在邏輯上等價,則返回 True;否則返回 False。
對於兩個引數,這相當於Xnor
。
例子
>>> from sympy.logic.boolalg import Equivalent, And
>>> from sympy.abc import x
>>> Equivalent(False, False, False)
True
>>> Equivalent(True, False, False)
False
>>> Equivalent(x, And(x, True))
True
class sympy.logic.boolalg.ITE(*args)
If-then-else 子句。
ITE(A, B, C)
評估並返回 B 的結果,如果 A 為真則返回 C 的結果。所有引數必須是布林值。
從邏輯閘的角度來看,ITE 對應於一個 2 到 1 的多路複用器,其中 A 是選擇訊號。
例子
>>> from sympy.logic.boolalg import ITE, And, Xor, Or
>>> from sympy.abc import x, y, z
>>> ITE(True, False, True)
False
>>> ITE(Or(True, False), And(True, True), Xor(True, True))
True
>>> ITE(x, y, z)
ITE(x, y, z)
>>> ITE(True, x, y)
x
>>> ITE(False, x, y)
y
>>> ITE(x, y, y)
y
嘗試使用非布林引數將生成一個 TypeError:
>>> ITE(True, [], ())
Traceback (most recent call last):
...
TypeError: expecting bool, Boolean or ITE, not `[]`
class sympy.logic.boolalg.Exclusive(*args)
當只有一個或沒有引數為真時為真。
Exclusive(A, B, C)
等效於 ~(A & B) & ~(A & C) & ~(B & C)
。
對於兩個引數,這相當於Xor
。
例子
>>> from sympy.logic.boolalg import Exclusive
>>> Exclusive(False, False, False)
True
>>> Exclusive(False, True, False)
True
>>> Exclusive(False, True, True)
False
以下函式可以用來處理代數、合取、析取和否定標準形式:
sympy.logic.boolalg.to_anf(expr, deep=True)
將expr
轉換為代數標準形式(ANF)。
ANF 是一個規範的標準形式,這意味著兩個等價的公式將轉換為相同的 ANF。
邏輯表示式處於 ANF 中,如果它具有以下形式
[1 \oplus a \oplus b \oplus ab \oplus abc]
即可以是:
-
純粹的真,
-
純粹的假,
-
變數的合取,
-
互斥的異或。
互斥的異或只能包含真、變數或變數的合取。不允許有否定。
如果deep
是False
,布林表示式的引數被視為變數,即只有頂層表示式轉換為 ANF。
例子
>>> from sympy.logic.boolalg import And, Or, Not, Implies, Equivalent
>>> from sympy.logic.boolalg import to_anf
>>> from sympy.abc import A, B, C
>>> to_anf(Not(A))
A ^ True
>>> to_anf(And(Or(A, B), Not(C)))
A ^ B ^ (A & B) ^ (A & C) ^ (B & C) ^ (A & B & C)
>>> to_anf(Implies(Not(A), Equivalent(B, C)), deep=False)
True ^ ~A ^ (~A & (Equivalent(B, C)))
sympy.logic.boolalg.to_cnf(expr, simplify=False, force=False)
將命題邏輯句子expr
轉換為合取正規化:((A | ~B | ...) & (B | C | ...) & ...)
。如果simplify
為True
,則使用 Quine-McCluskey 演算法將expr
評估為其最簡單的 CNF 形式;這可能需要很長時間。如果有超過 8 個變數,則必須將force
標誌設定為True
以進行簡化(預設為False
)。
例子
>>> from sympy.logic.boolalg import to_cnf
>>> from sympy.abc import A, B, D
>>> to_cnf(~(A | B) | D)
(D | ~A) & (D | ~B)
>>> to_cnf((A | B) & (A | ~A), True)
A | B
sympy.logic.boolalg.to_dnf(expr, simplify=False, force=False)
將命題邏輯句子expr
轉換為析取正規化:((A & ~B & ...) | (B & C & ...) | ...)
。如果simplify
為True
,則使用 Quine-McCluskey 演算法將expr
評估為其最簡單的 DNF 形式;這可能需要很長時間。如果有超過 8 個變數,則必須將force
標誌設定為True
以進行簡化(預設為False
)。
例子
>>> from sympy.logic.boolalg import to_dnf
>>> from sympy.abc import A, B, C
>>> to_dnf(B & (A | C))
(A & B) | (B & C)
>>> to_dnf((A & B) | (A & ~B) | (B & C) | (~B & C), True)
A | C
sympy.logic.boolalg.to_nnf(expr, simplify=True)
將expr
轉換為否定標準形式(NNF)。
邏輯表示式處於 NNF 中,如果它僅包含And
、Or
和Not
,並且Not
僅應用於文字。如果simplify
為True
,結果不包含多餘的子句。
例子
>>> from sympy.abc import A, B, C, D
>>> from sympy.logic.boolalg import Not, Equivalent, to_nnf
>>> to_nnf(Not((~A & ~B) | (C & D)))
(A | B) & (~C | ~D)
>>> to_nnf(Equivalent(A >> B, B >> A))
(A | ~B | (A & ~B)) & (B | ~A | (B & ~A))
sympy.logic.boolalg.is_anf(expr)
檢查expr
是否在代數標準形式(ANF)中。
邏輯表示式處於 ANF 中,如果它具有以下形式
[1 \oplus a \oplus b \oplus ab \oplus abc]
即它是純粹的真、純粹的假、變數的合取或互斥的異或。互斥的異或只能包含真、變數或變數的合取。不允許有否定。
例子
>>> from sympy.logic.boolalg import And, Not, Xor, true, is_anf
>>> from sympy.abc import A, B, C
>>> is_anf(true)
True
>>> is_anf(A)
True
>>> is_anf(And(A, B, C))
True
>>> is_anf(Xor(A, Not(B)))
False
sympy.logic.boolalg.is_cnf(expr)
測試表示式是否處於合取正規化中。
例子
>>> from sympy.logic.boolalg import is_cnf
>>> from sympy.abc import A, B, C
>>> is_cnf(A | B | C)
True
>>> is_cnf(A & B & C)
True
>>> is_cnf((A & B) | C)
False
sympy.logic.boolalg.is_dnf(expr)
測試表示式是否為析取正規化(DNF)。
示例
>>> from sympy.logic.boolalg import is_dnf
>>> from sympy.abc import A, B, C
>>> is_dnf(A | B | C)
True
>>> is_dnf(A & B & C)
True
>>> is_dnf((A & B) | C)
True
>>> is_dnf(A & (B | C))
False
sympy.logic.boolalg.is_nnf(expr, simplified=True)
檢查expr
是否處於否定正規化(NNF)。
邏輯表示式在 NNF 中,如果只包含And
、Or
和Not
,並且Not
僅應用於文字。如果simplified
為True
,則檢查結果是否不包含冗餘子句。
示例
>>> from sympy.abc import A, B, C
>>> from sympy.logic.boolalg import Not, is_nnf
>>> is_nnf(A & B | ~C)
True
>>> is_nnf((A | ~A) & (B | C))
False
>>> is_nnf((A | ~A) & (B | C), False)
True
>>> is_nnf(Not(A & B) | C)
False
>>> is_nnf((A >> B) & (B >> A))
False
sympy.logic.boolalg.gateinputcount(expr)
返回實現布林表示式的邏輯閘的總輸入數。
返回:
整數
門輸入數
注意
此處只有標準門才算作布林函式,包括:And
、Or
、Xor
、Not
和ITE
(多路複用器)。Nand
、Nor
和Xnor
將被計算為Not(And())
等。
示例
>>> from sympy.logic import And, Or, Nand, Not, gateinputcount
>>> from sympy.abc import x, y, z
>>> expr = And(x, y)
>>> gateinputcount(expr)
2
>>> gateinputcount(Or(expr, z))
4
注意,Nand
自動計算為Not(And())
,因此
>>> gateinputcount(Nand(x, y, z))
4
>>> gateinputcount(Not(And(x, y, z)))
4
儘管可以透過使用evaluate=False
來避免此問題
>>> gateinputcount(Nand(x, y, z, evaluate=False))
3
還要注意,比較將計為布林變數:
>>> gateinputcount(And(x > z, y >= 2))
2
如符號:>>> gateinputcount(x) 0
簡化和等價測試
sympy.logic.boolalg.simplify_logic(expr, form=None, deep=True, force=False, dontcare=None)
此函式將布林函式簡化為其標準形式中的簡化版本(SOP 或 POS)。返回型別是 SymPy 中的Or
或And
物件。
引數:
expr:布林值
form:字串('cnf'
或'dnf'
)或None
(預設)。
如果是
'cnf'
或'dnf'
,則返回相應正規形式中的最簡表示式;如果是None
,則根據引數最少的形式返回答案(預設為 CNF)。
deep:布林值(預設True
)
指示是否遞迴簡化輸入中包含的任何非布林函式。
force:布林值(預設False
)
由於簡化在變數數量的指數時間內,對具有 8 個以上變數的表示式預設有一個限制。當表示式超過 8 個變數時,只進行符號化簡化(由
deep
控制)。透過將force
設定為True
,可以移除此限制。請注意,這可能導致非常長的簡化時間。
dontcare:布林值
在假設這個表示式為真的輸入是不重要的情況下最佳化表示式。例如,在分段條件中很有用,後續條件不需要考慮前面條件轉換的輸入。例如,如果前面的條件是
And(A, B)
,則可以使用對And(A, B)
的不重要性簡化表示式。
示例
>>> from sympy.logic import simplify_logic
>>> from sympy.abc import x, y, z
>>> b = (~x & ~y & ~z) | ( ~x & ~y & z)
>>> simplify_logic(b)
~x & ~y
>>> simplify_logic(x | y, dontcare=y)
x
參考文獻
[R605]
不重要術語
SymPy 的simplify()
函式也可用於將邏輯表示式簡化為其最簡形式。
sympy.logic.boolalg.bool_map(bool1, bool2)
返回bool1的簡化版本,以及使兩個表示式bool1和bool2在變數之間的某種對應關係下表示相同邏輯行為的變數對映。如果存在多個這樣的對映,則返回其中一個。
例如,對於對映{x: a, y: b}
或{x: b, y: a}
,And(x, y)
在邏輯上等價於And(a, b)
。如果不存在這樣的對映,則返回False
。
示例
>>> from sympy import SOPform, bool_map, Or, And, Not, Xor
>>> from sympy.abc import w, x, y, z, a, b, c, d
>>> function1 = SOPform([x, z, y],[[1, 0, 1], [0, 0, 1]])
>>> function2 = SOPform([a, b, c],[[1, 0, 1], [1, 0, 0]])
>>> bool_map(function1, function2)
(y & ~z, {y: a, z: b})
結果不一定是唯一的,但它們是規範的。這裡,(w, z)
可以是(a, d)
或(d, a)
:
>>> eq = Or(And(Not(y), w), And(Not(y), z), And(x, y))
>>> eq2 = Or(And(Not(c), a), And(Not(c), d), And(b, c))
>>> bool_map(eq, eq2)
((x & y) | (w & ~y) | (z & ~y), {w: a, x: b, y: c, z: d})
>>> eq = And(Xor(a, b), c, And(c,d))
>>> bool_map(eq, eq.subs(c, x))
(c & d & (a | b) & (~a | ~b), {a: a, b: b, c: d, d: x})
操縱表示式
可以用來操作布林表示式的以下函式:
sympy.logic.boolalg.distribute_and_over_or(expr)
給定一個由文字的合取和析取組成的句子expr
,返回一個等價的 CNF 形式的句子。
示例
>>> from sympy.logic.boolalg import distribute_and_over_or, And, Or, Not
>>> from sympy.abc import A, B, C
>>> distribute_and_over_or(Or(A, And(Not(B), Not(C))))
(A | ~B) & (A | ~C)
sympy.logic.boolalg.distribute_or_over_and(expr)
給定一個由文字的合取和析取組成的句子expr
,返回一個等價的 DNF 形式的句子。
注意輸出未簡化。
示例
>>> from sympy.logic.boolalg import distribute_or_over_and, And, Or, Not
>>> from sympy.abc import A, B, C
>>> distribute_or_over_and(And(Or(Not(A), B), C))
(B & C) | (C & ~A)
sympy.logic.boolalg.distribute_xor_over_and(expr)
給定一個由文字的合取和排他析取組成的句子expr
,返回一個等價的排他析取。
注意輸出未簡化。
示例
>>> from sympy.logic.boolalg import distribute_xor_over_and, And, Xor, Not
>>> from sympy.abc import A, B, C
>>> distribute_xor_over_and(And(Xor(Not(A), B), C))
(B & C) ^ (C & ~A)
sympy.logic.boolalg.eliminate_implications(expr)
將Implies
和Equivalent
改為And
,Or
和Not
。也就是說,返回一個與expr
等價的表示式,但只使用&
、|
和~
作為邏輯運算子。
示例
>>> from sympy.logic.boolalg import Implies, Equivalent, eliminate_implications
>>> from sympy.abc import A, B, C
>>> eliminate_implications(Implies(A, B))
B | ~A
>>> eliminate_implications(Equivalent(A, B))
(A | ~B) & (B | ~A)
>>> eliminate_implications(Equivalent(A, B, C))
(A | ~C) & (B | ~A) & (C | ~B)
真值表及相關函式
可以建立布林函式的真值表。
sympy.logic.boolalg.truth_table(expr, variables, input=True)
返回輸入變數的所有可能配置的生成器,以及這些值的布林表示式的結果。
引數:
expr:布林表示式
variables:變數列表
input:布林值(預設為True
)
指示是否返回輸入組合。
示例
>>> from sympy.logic.boolalg import truth_table
>>> from sympy.abc import x,y
>>> table = truth_table(x >> y, [x, y])
>>> for t in table:
... print('{0} -> {1}'.format(*t))
[0, 0] -> True
[0, 1] -> True
[1, 0] -> False
[1, 1] -> True
>>> table = truth_table(x | y, [x, y])
>>> list(table)
[([0, 0], False), ([0, 1], True), ([1, 0], True), ([1, 1], True)]
如果input
為False
,truth_table
僅返回一個真值列表。在這種情況下,可以從給定輸出的索引推匯出變數的相應輸入值。
>>> from sympy.utilities.iterables import ibin
>>> vars = [y, x]
>>> values = truth_table(x >> y, vars, input=False)
>>> values = list(values)
>>> values
[True, False, True, True]
>>> for i, value in enumerate(values):
... print('{0} -> {1}'.format(list(zip(
... vars, ibin(i, len(vars)))), value))
[(y, 0), (x, 0)] -> True
[(y, 0), (x, 1)] -> False
[(y, 1), (x, 0)] -> True
[(y, 1), (x, 1)] -> True
為了在真值表位置的整數表示、零和一的列表以及符號之間進行對映,可以使用以下函式:
sympy.logic.boolalg.integer_to_term(n, bits=None, str=False)
返回長度為bits
的列表,該列表對應於表示n
的二進位制值,小位數在右邊(最後)。如果省略 bits,則長度將是表示n
所需的位數。如果希望以反向順序顯示位數,請使用返回列表的[::-1]
切片。
如果希望得到從[0, 0,..., 0]
到[1, 1, ..., 1]
的所有位長度列表的序列,則傳遞非整數作為位數,例如 'all'
。
如果需要位元串,則傳遞str=True
。
示例
>>> from sympy.utilities.iterables import ibin
>>> ibin(2)
[1, 0]
>>> ibin(2, 4)
[0, 0, 1, 0]
如果希望所有與 0 到\(2^n - 1\)對應的列表,請傳遞非整數作為位數:
>>> bits = 2
>>> for i in ibin(2, 'all'):
... print(i)
(0, 0)
(0, 1)
(1, 0)
(1, 1)
如果需要給定長度的位元串,請使用 str=True:
>>> n = 123
>>> bits = 10
>>> ibin(n, bits, str=True)
'0001111011'
>>> ibin(n, bits, str=True)[::-1] # small bits left
'1101111000'
>>> list(ibin(3, 'all', str=True))
['000', '001', '010', '011', '100', '101', '110', '111']
sympy.logic.boolalg.term_to_integer(term)
返回與項給定的基於二進位制的 2 進位制數相對應的整數。
引數:
項:字串或 1 和 0 列表
示例
>>> from sympy.logic.boolalg import term_to_integer
>>> term_to_integer([1, 0, 0])
4
>>> term_to_integer('100')
4
sympy.logic.boolalg.bool_maxterm(k, variables)
返回第 k 個最大項。
每個最大項根據用於最小項的傳統相反的二進位制編碼而分配一個索引。最大項的約定將直接形式分配值 0,補碼形式分配值 1。
引數:
k:整數或 1 和 0 列表(補碼模式)
變數:變數列表
示例
>>> from sympy.logic.boolalg import bool_maxterm
>>> from sympy.abc import x, y, z
>>> bool_maxterm([1, 0, 1], [x, y, z])
y | ~x | ~z
>>> bool_maxterm(6, [x, y, z])
z | ~x | ~y
參考文獻
[R606]
zh.wikipedia.org/wiki/正規正規化#最大項的索引
sympy.logic.boolalg.bool_minterm(k, variables)
返回第 k 個最小項。
最小項按變數的補碼模式的二進位制編碼編號。此約定將直接形式分配值 1,補碼形式分配值 0。
引數:
k:整數或 1 和 0 列表(補碼模式)
變數:變數列表
示例
>>> from sympy.logic.boolalg import bool_minterm
>>> from sympy.abc import x, y, z
>>> bool_minterm([1, 0, 1], [x, y, z])
x & z & ~y
>>> bool_minterm(6, [x, y, z])
x & y & ~z
參考文獻
[R607]
zh.wikipedia.org/wiki/正規正規化#最小項的索引
sympy.logic.boolalg.bool_monomial(k, variables)
返回第 k 個單項式。
單項式按變數的存在和不存在的二進位制編碼編號。此約定將變數的存在分配值 1,變數的不存在分配值 0。
每個布林函式都可以透過 Zhegalkin 多項式(代數正常形式)唯一表示。具有\(n\)個變數的布林函式的 Zhegalkin 多項式可以包含多達\(2^n\)個單項式。我們可以列舉所有的單項式。每個單項式由每個變數的存在或不存在來完全指定。
例如,具有四個變數(a, b, c, d)
的布林函式可以包含多達\(2⁴ = 16\)個單項式。第 13 個單項式是乘積a & b & d
,因為 13 在二進位制中是 1, 1, 0, 1。
引數:
k:整數或 1 和 0 列表
變數:變數列表
示例
>>> from sympy.logic.boolalg import bool_monomial
>>> from sympy.abc import x, y, z
>>> bool_monomial([1, 0, 1], [x, y, z])
x & z
>>> bool_monomial(6, [x, y, z])
x & y
sympy.logic.boolalg.anf_coeffs(truthvalues)
將某個布林表示式的真值列表轉換為在 ANF 中表示該布林表示式的多項式模 2 的係數列表(排他或)(即“Zhegalkin 多項式”)。
在(n)個變數中,Zhegalkin 單項式有(2^n)個可能,因為每個單項式透過每個變數的有無來完全指定。
我們可以列舉所有的單項式。例如,具有四個變數(a, b, c, d)
的布林函式可以包含最多(2⁴ = 16)個單項式。第 13 個單項式是乘積a & b & d
,因為 13 在二進位制中是 1, 1, 0, 1。
一個給定單項式在多項式中的出現與該單項式的係數分別為 1 或 0 相對應。
例子
>>> from sympy.logic.boolalg import anf_coeffs, bool_monomial, Xor
>>> from sympy.abc import a, b, c
>>> truthvalues = [0, 1, 1, 0, 0, 1, 0, 1]
>>> coeffs = anf_coeffs(truthvalues)
>>> coeffs
[0, 1, 1, 0, 0, 0, 1, 0]
>>> polynomial = Xor(*[
... bool_monomial(k, [a, b, c])
... for k, coeff in enumerate(coeffs) if coeff == 1
... ])
>>> polynomial
b ^ c ^ (a & b)
sympy.logic.boolalg.to_int_repr(clauses, symbols)
將 CNF 格式的子句轉換為整數表示。
例子
>>> from sympy.logic.boolalg import to_int_repr
>>> from sympy.abc import x, y
>>> to_int_repr([x | y, y], [x, y]) == [{1, 2}, {2}]
True
推斷
該模組實現了命題邏輯中的一些推斷例程。
函式satisfiable
將測試給定的布林表示式是否可滿足,即你可以為變數分配值使得句子為True
。
例如,表示式x & ~x
是不可滿足的,因為沒有任何值可以使得這個句子為True
。另一方面,(x | y) & (x | ~y) & (~x | y)
是可滿足的,其中x
和y
都為True
。
>>> from sympy.logic.inference import satisfiable
>>> from sympy import Symbol
>>> x = Symbol('x')
>>> y = Symbol('y')
>>> satisfiable(x & ~x)
False
>>> satisfiable((x | y) & (x | ~y) & (~x | y))
{x: True, y: True}
正如你所見,當一個句子是可滿足的時候,它會返回一個使得這個句子為True
的模型。如果它不可滿足,則會返回False
。
sympy.logic.inference.satisfiable(expr, algorithm=None, all_models=False, minimal=False, use_lra_theory=False)
檢查命題句子的可滿足性。當成功時返回一個模型。對於顯然為真的表示式,返回{true: true}
。
當將all_models
設定為 True 時,如果給定的表示式是可滿足的,則返回一個模型的生成器。然而,如果表示式是不可滿足的,則返回一個包含單一元素False
的生成器。
例子
>>> from sympy.abc import A, B
>>> from sympy.logic.inference import satisfiable
>>> satisfiable(A & ~B)
{A: True, B: False}
>>> satisfiable(A & ~A)
False
>>> satisfiable(True)
{True: True}
>>> next(satisfiable(A & ~A, all_models=True))
False
>>> models = satisfiable((A >> B) & B, all_models=True)
>>> next(models)
{A: False, B: True}
>>> next(models)
{A: True, B: True}
>>> def use_models(models):
... for model in models:
... if model:
... # Do something with the model.
... print(model)
... else:
... # Given expr is unsatisfiable.
... print("UNSAT")
>>> use_models(satisfiable(A >> ~A, all_models=True))
{A: False}
>>> use_models(satisfiable(A ^ A, all_models=True))
UNSAT