N维阵列#
用于SymPy的N维阵列模块。
提供了四个类来处理N维数组,由密集/稀疏(即是在内存中存储所有元素还是只存储非零元素)和可变/不可变(不可变类是SymPy对象,但在创建之后不能更改)。
实例#
以下示例显示了 Array
. 这是 ImmutableDenseNDimArray
,即一个不可变的稠密N维数组,其他类都是类似的。对于可变类,也可以在构造对象后更改元素值。
数组构造可以检测嵌套列表和元组的形状:
>>> from sympy import Array
>>> a1 = Array([[1, 2], [3, 4], [5, 6]])
>>> a1
[[1, 2], [3, 4], [5, 6]]
>>> a1.shape
(3, 2)
>>> a1.rank()
2
>>> from sympy.abc import x, y, z
>>> a2 = Array([[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]])
>>> a2
[[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]]
>>> a2.shape
(2, 2, 2)
>>> a2.rank()
3
否则,可以传递一个一维数组,后跟一个形状元组:
>>> m1 = Array(range(12), (3, 4))
>>> m1
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
>>> m2 = Array(range(12), (3, 2, 2))
>>> m2
[[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]]
>>> m2[1,1,1]
7
>>> m2.reshape(4, 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
切片支撑:
>>> m2[:, 1, 1]
[3, 7, 11]
元素导数:
>>> from sympy.abc import x, y, z
>>> m3 = Array([x**3, x*y, z])
>>> m3.diff(x)
[3*x**2, y, 0]
>>> m3.diff(z)
[0, 0, 1]
与其他SymPy表达式相乘的基本用法如下:
>>> (1+x)*m3
[x**3*(x + 1), x*y*(x + 1), z*(x + 1)]
要对N维数组的每个元素应用函数,请使用 applyfunc
:
>>> m3.applyfunc(lambda x: x/2)
[x**3/2, x*y/2, z/2]
N-dim数组可以通过 tolist()
方法:
>>> m2.tolist()
[[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]]
>>> isinstance(m2.tolist(), list)
True
如果秩为2,则可以使用 tomatrix()
:
>>> m1.tomatrix()
Matrix([
[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]])
产品和收缩#
阵列间张量积 \(A_{{i_1,\ldots,i_n}}\) 和 \(B_{{j_1,\ldots,j_m}}\) 创建组合数组 \(P = A \otimes B\) 定义为
\(P_{i_1,\ldots,i_n,j_1,\ldots,j_m} := A_{i_1,\ldots,i_n}\cdot B_{j_1,\ldots,j_m}.\)
它可以通过 tensorproduct(...)
:
>>> from sympy import Array, tensorproduct
>>> from sympy.abc import x,y,z,t
>>> A = Array([x, y, z, t])
>>> B = Array([1, 2, 3, 4])
>>> tensorproduct(A, B)
[[x, 2*x, 3*x, 4*x], [y, 2*y, 3*y, 4*y], [z, 2*z, 3*z, 4*z], [t, 2*t, 3*t, 4*t]]
In case you don't want to evaluate the tensor product immediately, you can use
ArrayTensorProduct
, which creates an unevaluated tensor product expression:
>>> from sympy.tensor.array.expressions import ArrayTensorProduct
>>> ArrayTensorProduct(A, B)
ArrayTensorProduct([x, y, z, t], [1, 2, 3, 4])
Calling .as_explicit()
on ArrayTensorProduct
is equivalent to just calling
tensorproduct(...)
:
>>> ArrayTensorProduct(A, B).as_explicit()
[[x, 2*x, 3*x, 4*x], [y, 2*y, 3*y, 4*y], [z, 2*z, 3*z, 4*z], [t, 2*t, 3*t, 4*t]]
秩1数组和矩阵之间的张量积创建秩3数组:
>>> from sympy import eye
>>> p1 = tensorproduct(A, eye(4))
>>> p1
[[[x, 0, 0, 0], [0, x, 0, 0], [0, 0, x, 0], [0, 0, 0, x]], [[y, 0, 0, 0], [0, y, 0, 0], [0, 0, y, 0], [0, 0, 0, y]], [[z, 0, 0, 0], [0, z, 0, 0], [0, 0, z, 0], [0, 0, 0, z]], [[t, 0, 0, 0], [0, t, 0, 0], [0, 0, t, 0], [0, 0, 0, t]]]
现在,回去吧 \(A_0 \otimes \mathbf{{1}}\) 一个人可以进入 \(p_{{0,m,n}}\) 通过切片:
>>> p1[0,:,:]
[[x, 0, 0, 0], [0, x, 0, 0], [0, 0, x, 0], [0, 0, 0, x]]
指定轴上的张量收缩和,例如收缩位置 \(a\) 和 \(b\) 方法
\(A_{i_1,\ldots,i_a,\ldots,i_b,\ldots,i_n} \implies \sum_k A_{i_1,\ldots,k,\ldots,k,\ldots,i_n}\)
请记住,Python索引是从零开始的,为了收缩a轴和b轴,因此有必要指定 \(a-1\) 和 \(b-1\)
>>> from sympy import tensorcontraction
>>> C = Array([[x, y], [z, t]])
矩阵轨迹相当于秩2数组的收缩:
\(A_{m,n} \implies \sum_k A_{k,k}\)
>>> tensorcontraction(C, (0, 1))
t + x
To create an expression representing a tensor contraction that does not get
evaluated immediately, use ArrayContraction
, which is equivalent to
tensorcontraction(...)
if it is followed by .as_explicit()
:
>>> from sympy.tensor.array.expressions import ArrayContraction
>>> ArrayContraction(C, (0, 1))
ArrayContraction([[x, y], [z, t]], (0, 1))
>>> ArrayContraction(C, (0, 1)).as_explicit()
t + x
矩阵积相当于两个秩2数组的张量积,然后是第2和第3个轴的收缩(在Python索引轴1,2中)。
\(A_{m,n}\cdot B_{i,j} \implies \sum_k A_{m, k}\cdot B_{k, j}\)
>>> D = Array([[2, 1], [0, -1]])
>>> tensorcontraction(tensorproduct(C, D), (1, 2))
[[2*x, x - y], [2*z, -t + z]]
可以验证矩阵乘积是否等效:
>>> from sympy import Matrix
>>> Matrix([[x, y], [z, t]])*Matrix([[2, 1], [0, -1]])
Matrix([
[2*x, x - y],
[2*z, -t + z]])
或等价地
>>> C.tomatrix()*D.tomatrix()
Matrix([
[2*x, x - y],
[2*z, -t + z]])
Diagonal operator#
The tensordiagonal
function acts in a similar manner as tensorcontraction
,
but the joined indices are not summed over, for example diagonalizing
positions \(a\) and \(b\) means
\(A_{i_1,\ldots,i_a,\ldots,i_b,\ldots,i_n} \implies A_{i_1,\ldots,k,\ldots,k,\ldots,i_n} \implies \tilde{A}_{i_1,\ldots,i_{a-1},i_{a+1},\ldots,i_{b-1},i_{b+1},\ldots,i_n,k}\)
where \(\tilde{A}\) is the array equivalent to the diagonal of \(A\) at positions \(a\) and \(b\) moved to the last index slot.
Compare the difference between contraction and diagonal operators:
>>> from sympy import tensordiagonal
>>> from sympy.abc import a, b, c, d
>>> m = Matrix([[a, b], [c, d]])
>>> tensorcontraction(m, [0, 1])
a + d
>>> tensordiagonal(m, [0, 1])
[a, d]
In short, no summation occurs with tensordiagonal
.
阵列导数#
如果数组中的所有元素都是适合派生的符号或表达式,则通常的派生操作可以扩展为支持对数组的派生。
数组对导数的定义如下:给定数组 \(A_{{i_1, \ldots, i_N}}\) 以及阵列 \(X_{{j_1, \ldots, j_M}}\) 数组的导数将返回一个新数组 \(B\) 由定义
\(B_{j_1,\ldots,j_M,i_1,\ldots,i_N} := \frac{\partial A_{i_1,\ldots,i_N}}{\partial X_{j_1,\ldots,j_M}}\)
函数 derive_by_array
执行这样的操作:
>>> from sympy import derive_by_array
>>> from sympy.abc import x, y, z, t
>>> from sympy import sin, exp
对于标量,它的行为与普通导数完全相同:
>>> derive_by_array(sin(x*y), x)
y*cos(x*y)
基于数组的标量:
>>> derive_by_array(sin(x*y), [x, y, z])
[y*cos(x*y), x*cos(x*y), 0]
以数组为基础导出数组: \(B^{{nm}} := \frac{{\partial A^m}}{{\partial x^n}}\)
>>> basis = [x, y, z]
>>> ax = derive_by_array([exp(x), sin(y*z), t], basis)
>>> ax
[[exp(x), 0, 0], [0, z*cos(y*z), 0], [0, y*cos(y*z), 0]]
结果数组的收缩: \(\sum_m \frac{{\partial A^m}}{{\partial x^m}}\)
>>> tensorcontraction(ax, (0, 1))
z*cos(y*z) + exp(x)
Classes#
功能#
- sympy.tensor.array.derive_by_array(expr, dx)[源代码]#
数组的导数。同时支持数组和标量。
The equivalent operator for array expressions is
array_derive
.解释
给定数组 \(A_{{i_1, \ldots, i_N}}\) 以及阵列 \(X_{{j_1, \ldots, j_M}}\) 此函数将返回一个新数组 \(B\) 由定义
\(B_{j_1,\ldots,j_M,i_1,\ldots,i_N} := \frac{\partial A_{i_1,\ldots,i_N}}{\partial X_{j_1,\ldots,j_M}}\)
实例
>>> from sympy import derive_by_array >>> from sympy.abc import x, y, z, t >>> from sympy import cos >>> derive_by_array(cos(x*t), x) -t*sin(t*x) >>> derive_by_array(cos(x*t), [x, y, z, t]) [-t*sin(t*x), 0, 0, -x*sin(t*x)] >>> derive_by_array([x, y**2*z], [[x, y], [z, t]]) [[[1, 0], [0, 2*y*z]], [[0, y**2], [0, 0]]]
- sympy.tensor.array.permutedims(expr, perm=None, index_order_old=None, index_order_new=None)[源代码]#
排列数组的索引。
参数指定索引的排列。
The equivalent operator for array expressions is
PermuteDims
, which can be used to keep the expression unevaluated.实例
>>> from sympy.abc import x, y, z, t >>> from sympy import sin >>> from sympy import Array, permutedims >>> a = Array([[x, y, z], [t, sin(x), 0]]) >>> a [[x, y, z], [t, sin(x), 0]] >>> permutedims(a, (1, 0)) [[x, t], [y, sin(x)], [z, 0]]
如果数组是二阶的,
transpose
可用于:>>> from sympy import transpose >>> transpose(a) [[x, t], [y, sin(x)], [z, 0]]
更高维度的示例:
>>> b = Array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) >>> permutedims(b, (2, 1, 0)) [[[1, 5], [3, 7]], [[2, 6], [4, 8]]] >>> permutedims(b, (1, 2, 0)) [[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
An alternative way to specify the same permutations as in the previous lines involves passing the old and new indices, either as a list or as a string:
>>> permutedims(b, index_order_old="cba", index_order_new="abc") [[[1, 5], [3, 7]], [[2, 6], [4, 8]]] >>> permutedims(b, index_order_old="cab", index_order_new="abc") [[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
Permutation
还允许使用对象:>>> from sympy.combinatorics import Permutation >>> permutedims(b, Permutation([1, 2, 0])) [[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
- sympy.tensor.array.tensorcontraction(array, *contraction_axes)[源代码]#
在指定轴上压缩类似数组的对象。
The equivalent operator for array expressions is
ArrayContraction
, which can be used to keep the expression unevaluated.实例
>>> from sympy import Array, tensorcontraction >>> from sympy import Matrix, eye >>> tensorcontraction(eye(3), (0, 1)) 3 >>> A = Array(range(18), (3, 2, 3)) >>> A [[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]], [[12, 13, 14], [15, 16, 17]]] >>> tensorcontraction(A, (0, 2)) [21, 30]
矩阵乘法可以用
tensorcontraction
和tensorproduct
>>> from sympy import tensorproduct >>> from sympy.abc import a,b,c,d,e,f,g,h >>> m1 = Matrix([[a, b], [c, d]]) >>> m2 = Matrix([[e, f], [g, h]]) >>> p = tensorproduct(m1, m2) >>> p [[[[a*e, a*f], [a*g, a*h]], [[b*e, b*f], [b*g, b*h]]], [[[c*e, c*f], [c*g, c*h]], [[d*e, d*f], [d*g, d*h]]]] >>> tensorcontraction(p, (1, 2)) [[a*e + b*g, a*f + b*h], [c*e + d*g, c*f + d*h]] >>> m1*m2 Matrix([ [a*e + b*g, a*f + b*h], [c*e + d*g, c*f + d*h]])
- sympy.tensor.array.tensorproduct(*args)[源代码]#
标量或类数组对象之间的张量积。
The equivalent operator for array expressions is
ArrayTensorProduct
, which can be used to keep the expression unevaluated.实例
>>> from sympy.tensor.array import tensorproduct, Array >>> from sympy.abc import x, y, z, t >>> A = Array([[1, 2], [3, 4]]) >>> B = Array([x, y]) >>> tensorproduct(A, B) [[[x, y], [2*x, 2*y]], [[3*x, 3*y], [4*x, 4*y]]] >>> tensorproduct(A, x) [[x, 2*x], [3*x, 4*x]] >>> tensorproduct(A, B, B) [[[[x**2, x*y], [x*y, y**2]], [[2*x**2, 2*x*y], [2*x*y, 2*y**2]]], [[[3*x**2, 3*x*y], [3*x*y, 3*y**2]], [[4*x**2, 4*x*y], [4*x*y, 4*y**2]]]]
对两个矩阵应用此函数将得到一个秩为4的数组。
>>> from sympy import Matrix, eye >>> m = Matrix([[x, y], [z, t]]) >>> p = tensorproduct(eye(3), m) >>> p [[[[x, y], [z, t]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[x, y], [z, t]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[x, y], [z, t]]]]
- sympy.tensor.array.tensordiagonal(array, *diagonal_axes)[源代码]#
Diagonalization of an array-like object on the specified axes.
This is equivalent to multiplying the expression by Kronecker deltas uniting the axes.
The diagonal indices are put at the end of the axes.
The equivalent operator for array expressions is
ArrayDiagonal
, which can be used to keep the expression unevaluated.实例
tensordiagonal
acting on a 2-dimensional array by axes 0 and 1 is equivalent to the diagonal of the matrix:>>> from sympy import Array, tensordiagonal >>> from sympy import Matrix, eye >>> tensordiagonal(eye(3), (0, 1)) [1, 1, 1]
>>> from sympy.abc import a,b,c,d >>> m1 = Matrix([[a, b], [c, d]]) >>> tensordiagonal(m1, [0, 1]) [a, d]
In case of higher dimensional arrays, the diagonalized out dimensions are appended removed and appended as a single dimension at the end:
>>> A = Array(range(18), (3, 2, 3)) >>> A [[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]], [[12, 13, 14], [15, 16, 17]]] >>> tensordiagonal(A, (0, 2)) [[0, 7, 14], [3, 10, 17]] >>> from sympy import permutedims >>> tensordiagonal(A, (0, 2)) == permutedims(Array([A[0, :, 0], A[1, :, 1], A[2, :, 2]]), [1, 0]) True