文章目录
基于计算机的科学计算有两种思路,一是将一切数值化,将所有已知的运算规律封装成函数,特定问题,返回特定的数值结果;二是将一切推理化,将各种数学问题,用符号系统来完成推导,此即符号计算。Python中,sympy是最基础的符号计算库。
符号计算
【sympy】是Python的符号计算库,可以实现下面这种功能
∫ c o s x d x = s i n x ∂ x ∂ e x y z = y z e x y z ∫cosxdx=sinx∂x∂exyz=yzexyz ∫cosxdx=sinx∂x∂exyz=yzexyz
那么从安装完sympy到实现上述功能,大概需要几步呢?下面就从头缕一缕。
首先, x , y , z x,y,z x,y,z肯定都是变量,而且是比较特殊的变量,最起码不是数值,而是个符号。在sympy中,创建一个符号需要调用【symbols】函数
import sympy
x, y, z = sympy.symbols('x y z')
print(x+1) # x + 1
有了符号就可以符号运算了。
from sympy import cos, exp, diff, integrate
integrate(cos(x), x) # sin(x)
diff(exp(x*y*z), x) # y*z*exp(x*y*z)
其中,
- 【diff】求导函数,输入为表达式和待求导分量
- 【integrate】用于积分,输入为表达式和待积分的分量
- 【cos, exp】余弦和指数函数,sympy中封装了一系列基础函数,名称与numpy中几乎完全相同,但主要被用作符号计算。
符号赋值和画图
符号计算往往也需要得到数值结果的,【evalf】函数便可以胜任这项工作,其参数subs通过字典的形式,一一指定自变量。
f = sympy.diff(sympy.exp(x*y*z),x)
f.evalf(subs={x:1, y:1, z:1}) # 2.71828182845905
单点赋值显然没有什么表现力,下面让 x , y x,y x,y等于1,得到一个关于 z z z的函数 g ( z ) = z e z g(z)=zez g(z)=zez的曲线。这个流程分为两步,首先进行变量代换得到 g g g函数,再绘制 g g g的图像:
g = f.subs([(x,1), (y,1)])
print(g) # z*exp(z)
sympy.plot(g, xlim=(0,5), ylim=(0,1000))
其中,
- 【subs】方法用于变量代换,其输入为元组列表,每个元组都代表一个替换对。
- 【plot】函数用于绘图,xlim, ylim用于指定 x , y x,y x,y轴的范围,绘图结果如下
sympy提供了三维绘图能力,接下来指定 x = 1 x=1 x=1,构造函数 h = y z l n ( y z ) h=yzln(yz) h=yzln(yz),并绘制其在三维坐标中的图像
h = f.subs(x, 1)
h = sympy.log(h)
sympy.plotting.plot3d(h)
除了这些常规的画图,sympy甚至支持在命令行中绘图,十分离谱
>>> sympy.textplot(x**2, -5, 5)
25 |\ /
| . .
|
| . .
| \ /
| . .
|
| . .
| \ /
| \ /
12.5 |--------\-------------------------------------/--------
| \ /
| \ /
| \ /
| \ /
| .. ..
| \ /
| .. ..
| .. ..
| ... ...
0 |_______________________________________________________
-5 0 5
化简
对于符号计算来说,化简是一个非常重要的功能,一个缺乏可读性的解析表达式是毫无价值的。在sympy中,提供了simplify可对解析表达式进行化简。以下式为例
x s i n 2 ( y ) + x c o s 2 ( y ) x 2 + x = x + 1 xsin2(y)+xcos2(y)x2+x=x+1 xsin2(y)+xcos2(y)x2+x=x+1
只需用sympy将这个表达式复现出来,然后调用simplify即可
from sympy import simplify, cos, sin
a = (x + x2)/(x*sin(y)2 + x*cos(y)**2)
aSim = simplify(a)
公式输出
对于复杂公式,可读性是一个很大的问题,sympy自然想到了这个刚需,提供了更加漂亮的公式输出,例如通过设置【init_session】,可以在命令行中输出更加漂亮的格式,唯一需要注意的是,在使用这个命令之后,会重新导入sympy
,从而导致此前的工作区清空,所以,这个功能最好一开始就使用,下面是在jupyter notebook
中调用的结果
如果想写在文档里,还可以直接输出latex
源代码
sympy.latex(integrate(exp(x)/(exp(2*x) + 1), x))
#返回值 \operatorname{RootSum} {\left(4 z^{2} + 1, \left( i \mapsto i \log{\left(2 i + e^{x} \right)} \right)\right)}