使用 sympy 扩展索引符号方程
Expand index notation equation using sympy
下面我有一个用索引符号写的等式。这个方程可以用图中的六个方程来表示。
第一个方程使用索引符号展开(爱因斯坦符号:https://en.wikipedia.org/wiki/Einstein_notation)。
在 U_k,k 中,逗号是导数的约定。由于我们有重复的索引 (k,k),我们应用求和约定并得到 (du_1/dx_1 + du_2/dx_2 + du_3/dx_3)。图中u_1、u_2、u_3分别写为u、v、w,用x_1、x_2、[=29区分=](x、y 和 z)。
我是 python 和 Sympy 的新手,我看到有一个张量模块,但我看不到 Sympy 中是否已经实现了一些东西,我可以在其中编写第一个方程(带索引)和从中获得其他六个关系。
目前,没有直接的方法来完成您的要求。
我将建议一个应该有效的技巧,方法是使用 IndexedBase(即由其他符号索引的符号),然后进行替换。
声明你的符号:
U = IndexedBase("U")
l = symbols("lambda")
var("mu u v w x y z i j k")
声明你的表达式(没有爱因斯坦求和,所以明确地输入一个Sum):
sij = l*Sum(U[k, k], (k, 0, 2)) * KroneckerDelta(i, j) + mu*(U[i, j] + U[j, i])
定义一个替换函数:将U[0, 0]匹配到Derivative(u, x)等指数:
def replace_U(uij):
i1, i2 = uij.indices
return Derivative([u, v, w][i1], [x, y, z][i2])
现在,运行 全部 i,j 索引替换 U[i, j] 首先使用整数值,然后替换 U[0, 0], ...
等表达式
for ii in range(3):
for ji in range(3):
if ii < ji:
continue
pprint(sij.doit().xreplace({i: ii, j: ji}).replace(lambda v: v.base == U, replace_U))
记住:Sum.doit() 展开求和。条件 ii >= ji 用于避免打印相同的表达式两次(你的等式在 i, j 中是对称的)。
注意上面代码中的U[i,j]只是一个符号,i和j 除了作为 U 的索引外没有特殊意义。替换函数为它们分配导数。
我得到的输出是:
⎛d d d ⎞ d
λ⋅⎜──(u) + ──(v) + ──(w)⎟ + 2⋅μ⋅──(u)
⎝dx dy dz ⎠ dx
⎛d d ⎞
μ⋅⎜──(u) + ──(v)⎟
⎝dy dx ⎠
⎛d d d ⎞ d
λ⋅⎜──(u) + ──(v) + ──(w)⎟ + 2⋅μ⋅──(v)
⎝dx dy dz ⎠ dy
⎛d d ⎞
μ⋅⎜──(u) + ──(w)⎟
⎝dz dx ⎠
⎛d d ⎞
μ⋅⎜──(v) + ──(w)⎟
⎝dz dy ⎠
⎛d d d ⎞ d
λ⋅⎜──(u) + ──(v) + ──(w)⎟ + 2⋅μ⋅──(w)
⎝dx dy dz ⎠ dz
I am new to python and Sympy and I saw that there is a tensor module
but I could not see if there is something already implemented in Sympy
where I can write the first equation (with index) and from that obtain
the other six relations.
有sympy.tensor.tensor,支持抽象索引符号(一种受限的爱因斯坦求和)。不幸的是,它不支持衍生品。
如果您想处理组件,最近添加了一个:sympy.tensor.array。它提供了多维数组、张量积和收缩以及数组的导数。
如Francesco Bonazzi stated, there is another way to implement equations using sympy.tensor.array。这种方法的优点是容易实现导数
示例代码(jupyter)如下:
from sympy import *
lam, mu, x, y, z = symbols("lambda mu x y z")
u, v, w = symbols("u v w", cls=Function)
du = derive_by_array([u(x, y, z), v(x, y, z), w(x, y, z)], [x, y, z])
sig = lam * tensorcontraction(du, (0, 1)) * Array(eye(3)) + mu * (du + transpose(du))
for i in range(3):
for j in range(i, 3):
display(Eq(Symbol("sigma_{}{}".format(i+1, j+1)), sig[i, j]))
输出:
这是我对这个问题的回答。代码 displays/prints 结果并没有给出错误,因为它是根据索引符号计算的。
欢迎就进一步 (i) 适合科学出版物的优化和打印结果提出意见。目前看起来很别扭。
from sympy import Symbol, Derivative
from sympy import *
lam, mu, x, y, z = symbols("lambda mu x y z")
u, v, w = symbols("u v w", cls=Function)
du = derive_by_array([u(x, y, z), v(x, y, z), w(x, y, z)], [x, y, z])
sig = lam * tensorcontraction(du, (0, 1))*Array(eye(3)) + mu * (du + transpose(du))
alist = []
for i in range(3):
for j in range(i, 3):
alist.append(Eq(Symbol("sigma_{}{}".format(i+1, j+1)), sig[i, j]))
init_printing()
下面我有一个用索引符号写的等式。这个方程可以用图中的六个方程来表示。
第一个方程使用索引符号展开(爱因斯坦符号:https://en.wikipedia.org/wiki/Einstein_notation)。 在 U_k,k 中,逗号是导数的约定。由于我们有重复的索引 (k,k),我们应用求和约定并得到 (du_1/dx_1 + du_2/dx_2 + du_3/dx_3)。图中u_1、u_2、u_3分别写为u、v、w,用x_1、x_2、[=29区分=](x、y 和 z)。
我是 python 和 Sympy 的新手,我看到有一个张量模块,但我看不到 Sympy 中是否已经实现了一些东西,我可以在其中编写第一个方程(带索引)和从中获得其他六个关系。
目前,没有直接的方法来完成您的要求。
我将建议一个应该有效的技巧,方法是使用 IndexedBase(即由其他符号索引的符号),然后进行替换。
声明你的符号:
U = IndexedBase("U")
l = symbols("lambda")
var("mu u v w x y z i j k")
声明你的表达式(没有爱因斯坦求和,所以明确地输入一个Sum):
sij = l*Sum(U[k, k], (k, 0, 2)) * KroneckerDelta(i, j) + mu*(U[i, j] + U[j, i])
定义一个替换函数:将U[0, 0]匹配到Derivative(u, x)等指数:
def replace_U(uij):
i1, i2 = uij.indices
return Derivative([u, v, w][i1], [x, y, z][i2])
现在,运行 全部 i,j 索引替换 U[i, j] 首先使用整数值,然后替换 U[0, 0], ...
等表达式for ii in range(3):
for ji in range(3):
if ii < ji:
continue
pprint(sij.doit().xreplace({i: ii, j: ji}).replace(lambda v: v.base == U, replace_U))
记住:Sum.doit() 展开求和。条件 ii >= ji 用于避免打印相同的表达式两次(你的等式在 i, j 中是对称的)。
注意上面代码中的U[i,j]只是一个符号,i和j 除了作为 U 的索引外没有特殊意义。替换函数为它们分配导数。
我得到的输出是:
⎛d d d ⎞ d
λ⋅⎜──(u) + ──(v) + ──(w)⎟ + 2⋅μ⋅──(u)
⎝dx dy dz ⎠ dx
⎛d d ⎞
μ⋅⎜──(u) + ──(v)⎟
⎝dy dx ⎠
⎛d d d ⎞ d
λ⋅⎜──(u) + ──(v) + ──(w)⎟ + 2⋅μ⋅──(v)
⎝dx dy dz ⎠ dy
⎛d d ⎞
μ⋅⎜──(u) + ──(w)⎟
⎝dz dx ⎠
⎛d d ⎞
μ⋅⎜──(v) + ──(w)⎟
⎝dz dy ⎠
⎛d d d ⎞ d
λ⋅⎜──(u) + ──(v) + ──(w)⎟ + 2⋅μ⋅──(w)
⎝dx dy dz ⎠ dz
I am new to python and Sympy and I saw that there is a tensor module but I could not see if there is something already implemented in Sympy where I can write the first equation (with index) and from that obtain the other six relations.
有sympy.tensor.tensor,支持抽象索引符号(一种受限的爱因斯坦求和)。不幸的是,它不支持衍生品。
如果您想处理组件,最近添加了一个:sympy.tensor.array。它提供了多维数组、张量积和收缩以及数组的导数。
如Francesco Bonazzi stated, there is another way to implement equations using sympy.tensor.array。这种方法的优点是容易实现导数
示例代码(jupyter)如下:
from sympy import *
lam, mu, x, y, z = symbols("lambda mu x y z")
u, v, w = symbols("u v w", cls=Function)
du = derive_by_array([u(x, y, z), v(x, y, z), w(x, y, z)], [x, y, z])
sig = lam * tensorcontraction(du, (0, 1)) * Array(eye(3)) + mu * (du + transpose(du))
for i in range(3):
for j in range(i, 3):
display(Eq(Symbol("sigma_{}{}".format(i+1, j+1)), sig[i, j]))
输出:
这是我对这个问题的回答。代码 displays/prints 结果并没有给出错误,因为它是根据索引符号计算的。
欢迎就进一步 (i) 适合科学出版物的优化和打印结果提出意见。目前看起来很别扭。
from sympy import Symbol, Derivative
from sympy import *
lam, mu, x, y, z = symbols("lambda mu x y z")
u, v, w = symbols("u v w", cls=Function)
du = derive_by_array([u(x, y, z), v(x, y, z), w(x, y, z)], [x, y, z])
sig = lam * tensorcontraction(du, (0, 1))*Array(eye(3)) + mu * (du + transpose(du))
alist = []
for i in range(3):
for j in range(i, 3):
alist.append(Eq(Symbol("sigma_{}{}".format(i+1, j+1)), sig[i, j]))
init_printing()