N-dim array expressions#
Array expressions are expressions representing N-dimensional arrays, without evaluating them. These expressions represent in a certain way abstract syntax trees of operations on N-dimensional arrays.
Every N-dimensional array operator has a corresponding array expression object.
Table of correspondences:
Array operator |
Array expression operator |
---|---|
tensorproduct |
ArrayTensorProduct |
tensorcontraction |
ArrayContraction |
tensordiagonal |
ArrayDiagonal |
permutedims |
PermuteDims |
实例#
ArraySymbol
objects are the N-dimensional equivalent of MatrixSymbol
objects in the matrix module:
>>> from sympy.tensor.array.expressions import ArraySymbol
>>> from sympy.abc import i, j, k
>>> A = ArraySymbol("A", (3, 2, 4))
>>> A.shape
(3, 2, 4)
>>> A[i, j, k]
A[i, j, k]
>>> A.as_explicit()
[[[A[0, 0, 0], A[0, 0, 1], A[0, 0, 2], A[0, 0, 3]],
[A[0, 1, 0], A[0, 1, 1], A[0, 1, 2], A[0, 1, 3]]],
[[A[1, 0, 0], A[1, 0, 1], A[1, 0, 2], A[1, 0, 3]],
[A[1, 1, 0], A[1, 1, 1], A[1, 1, 2], A[1, 1, 3]]],
[[A[2, 0, 0], A[2, 0, 1], A[2, 0, 2], A[2, 0, 3]],
[A[2, 1, 0], A[2, 1, 1], A[2, 1, 2], A[2, 1, 3]]]]
Component-explicit arrays can be added inside array expressions:
>>> from sympy import Array
>>> from sympy import tensorproduct
>>> from sympy.tensor.array.expressions import ArrayTensorProduct
>>> a = Array([1, 2, 3])
>>> b = Array([i, j, k])
>>> expr = ArrayTensorProduct(a, b, b)
>>> expr
ArrayTensorProduct([1, 2, 3], [i, j, k], [i, j, k])
>>> expr.as_explicit() == tensorproduct(a, b, b)
True
Constructing array expressions from index-explicit forms#
Array expressions are index-implicit. This means they do not use any indices to
represent array operations. The function convert_indexed_to_array( ... )
may be used to convert index-explicit expressions to array expressions.
It takes as input two parameters: the index-explicit expression and the order
of the indices:
>>> from sympy.tensor.array.expressions import convert_indexed_to_array
>>> from sympy import Sum
>>> A = ArraySymbol("A", (3, 3))
>>> B = ArraySymbol("B", (3, 3))
>>> convert_indexed_to_array(A[i, j], [i, j])
A
>>> convert_indexed_to_array(A[i, j], [j, i])
PermuteDims(A, (0 1))
>>> convert_indexed_to_array(A[i, j] + B[j, i], [i, j])
ArrayAdd(A, PermuteDims(B, (0 1)))
>>> convert_indexed_to_array(Sum(A[i, j]*B[j, k], (j, 0, 2)), [i, k])
ArrayContraction(ArrayTensorProduct(A, B), (1, 2))
The diagonal of a matrix in the array expression form:
>>> convert_indexed_to_array(A[i, i], [i])
ArrayDiagonal(A, (0, 1))
The trace of a matrix in the array expression form:
>>> convert_indexed_to_array(Sum(A[i, i], (i, 0, 2)), [i])
ArrayContraction(A, (0, 1))
Compatibility with matrices#
Array expressions can be mixed with objects from the matrix module:
>>> from sympy import MatrixSymbol
>>> from sympy.tensor.array.expressions import ArrayContraction
>>> M = MatrixSymbol("M", 3, 3)
>>> N = MatrixSymbol("N", 3, 3)
Express the matrix product in the array expression form:
>>> from sympy.tensor.array.expressions import convert_matrix_to_array
>>> expr = convert_matrix_to_array(M*N)
>>> expr
ArrayContraction(ArrayTensorProduct(M, N), (1, 2))
The expression can be converted back to matrix form:
>>> from sympy.tensor.array.expressions import convert_array_to_matrix
>>> convert_array_to_matrix(expr)
M*N
Add a second contraction on the remaining axes in order to get the trace of \(M \cdot N\):
>>> expr_tr = ArrayContraction(expr, (0, 1))
>>> expr_tr
ArrayContraction(ArrayContraction(ArrayTensorProduct(M, N), (1, 2)), (0, 1))
Flatten the expression by calling .doit()
and remove the nested array contraction operations:
>>> expr_tr.doit()
ArrayContraction(ArrayTensorProduct(M, N), (0, 3), (1, 2))
Get the explicit form of the array expression:
>>> expr.as_explicit()
[[M[0, 0]*N[0, 0] + M[0, 1]*N[1, 0] + M[0, 2]*N[2, 0], M[0, 0]*N[0, 1] + M[0, 1]*N[1, 1] + M[0, 2]*N[2, 1], M[0, 0]*N[0, 2] + M[0, 1]*N[1, 2] + M[0, 2]*N[2, 2]],
[M[1, 0]*N[0, 0] + M[1, 1]*N[1, 0] + M[1, 2]*N[2, 0], M[1, 0]*N[0, 1] + M[1, 1]*N[1, 1] + M[1, 2]*N[2, 1], M[1, 0]*N[0, 2] + M[1, 1]*N[1, 2] + M[1, 2]*N[2, 2]],
[M[2, 0]*N[0, 0] + M[2, 1]*N[1, 0] + M[2, 2]*N[2, 0], M[2, 0]*N[0, 1] + M[2, 1]*N[1, 1] + M[2, 2]*N[2, 1], M[2, 0]*N[0, 2] + M[2, 1]*N[1, 2] + M[2, 2]*N[2, 2]]]
Express the trace of a matrix:
>>> from sympy import Trace
>>> convert_matrix_to_array(Trace(M))
ArrayContraction(M, (0, 1))
>>> convert_matrix_to_array(Trace(M*N))
ArrayContraction(ArrayTensorProduct(M, N), (0, 3), (1, 2))
Express the transposition of a matrix (will be expressed as a permutation of the axes:
>>> convert_matrix_to_array(M.T)
PermuteDims(M, (0 1))
Compute the derivative array expressions:
>>> from sympy.tensor.array.expressions import array_derive
>>> d = array_derive(M, M)
>>> d
PermuteDims(ArrayTensorProduct(I, I), (3)(1 2))
Verify that the derivative corresponds to the form computed with explicit matrices:
>>> d.as_explicit()
[[[[1, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 1, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 1], [0, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [1, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 1], [0, 0, 0]]], [[[0, 0, 0], [0, 0, 0], [1, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 1, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 1]]]]
>>> Me = M.as_explicit()
>>> Me.diff(Me)
[[[[1, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 1, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 1], [0, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [1, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 1], [0, 0, 0]]], [[[0, 0, 0], [0, 0, 0], [1, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 1, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 1]]]]
- class sympy.tensor.array.expressions.ArrayContraction(expr, *contraction_indices, **kwargs)[源代码]#
这个类的目的是以代码打印机易于处理的形式表示数组的收缩。
- class sympy.tensor.array.expressions.ArrayDiagonal(expr, *diagonal_indices, **kwargs)[源代码]#
类来表示对角线运算符。
解释
在二维数组中,它返回对角线,如下所示:
\(A_{ij} \rightarrow A_{ii}\)
两个二维阵列张量积在轴1和轴2(第二和第三)上的对角线 \(A \otimes B\) 是
\(\Big[ A_{ab} B_{cd} \Big]_{abcd} \rightarrow \Big[ A_{ai} B_{id} \Big]_{adi}\)
在最后一个示例中,数组表达式已从四维缩减为三维。请注意,没有出现收缩,而是出现了一个新的指数 \(i\) 对于对角线,收缩会将数组减少到二维。
请注意,将对角化的out维度作为新维度添加到索引末尾。
- class sympy.tensor.array.expressions.PermuteDims(expr, permutation=None, index_order_old=None, index_order_new=None, **kwargs)[源代码]#
类来表示数组轴的排列。
实例
>>> from sympy.tensor.array import permutedims >>> from sympy import MatrixSymbol >>> M = MatrixSymbol("M", 3, 3) >>> cg = permutedims(M, [1, 0])
客体
cg
表示M
,作为排列[1, 0]
将通过切换指数来执行:\(M_{ij} \Rightarrow M_{ji}\)
这在转换回矩阵形式时很明显:
>>> from sympy.tensor.array.expressions.from_array_to_matrix import convert_array_to_matrix >>> convert_array_to_matrix(cg) M.T
>>> N = MatrixSymbol("N", 3, 2) >>> cg = permutedims(N, [1, 0]) >>> cg.shape (2, 3)
There are optional parameters that can be used as alternative to the permutation:
>>> from sympy.tensor.array.expressions import ArraySymbol, PermuteDims >>> M = ArraySymbol("M", (1, 2, 3, 4, 5)) >>> expr = PermuteDims(M, index_order_old="ijklm", index_order_new="kijml") >>> expr PermuteDims(M, (0 2 1)(3 4)) >>> expr.shape (3, 1, 2, 5, 4)
Permutations of tensor products are simplified in order to achieve a standard form:
>>> from sympy.tensor.array import tensorproduct >>> M = MatrixSymbol("M", 4, 5) >>> tp = tensorproduct(M, N) >>> tp.shape (4, 5, 3, 2) >>> perm1 = permutedims(tp, [2, 3, 1, 0])
The args
(M, N)
have been sorted and the permutation has been simplified, the expression is equivalent:>>> perm1.expr.args (N, M) >>> perm1.shape (3, 2, 5, 4) >>> perm1.permutation (2 3)
The permutation in its array form has been simplified from
[2, 3, 1, 0]
to[0, 1, 3, 2]
, as the arguments of the tensor product \(M\) and \(N\) have been switched:>>> perm1.permutation.array_form [0, 1, 3, 2]
We can nest a second permutation:
>>> perm2 = permutedims(perm1, [1, 0, 2, 3]) >>> perm2.shape (2, 3, 5, 4) >>> perm2.permutation.array_form [1, 0, 3, 2]