图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
7.1 KiB

  1. r"""
  2. N-dim array module for SymPy.
  3. Four classes are provided to handle N-dim arrays, given by the combinations
  4. dense/sparse (i.e. whether to store all elements or only the non-zero ones in
  5. memory) and mutable/immutable (immutable classes are SymPy objects, but cannot
  6. change after they have been created).
  7. Examples
  8. ========
  9. The following examples show the usage of ``Array``. This is an abbreviation for
  10. ``ImmutableDenseNDimArray``, that is an immutable and dense N-dim array, the
  11. other classes are analogous. For mutable classes it is also possible to change
  12. element values after the object has been constructed.
  13. Array construction can detect the shape of nested lists and tuples:
  14. >>> from sympy import Array
  15. >>> a1 = Array([[1, 2], [3, 4], [5, 6]])
  16. >>> a1
  17. [[1, 2], [3, 4], [5, 6]]
  18. >>> a1.shape
  19. (3, 2)
  20. >>> a1.rank()
  21. 2
  22. >>> from sympy.abc import x, y, z
  23. >>> a2 = Array([[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]])
  24. >>> a2
  25. [[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]]
  26. >>> a2.shape
  27. (2, 2, 2)
  28. >>> a2.rank()
  29. 3
  30. Otherwise one could pass a 1-dim array followed by a shape tuple:
  31. >>> m1 = Array(range(12), (3, 4))
  32. >>> m1
  33. [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
  34. >>> m2 = Array(range(12), (3, 2, 2))
  35. >>> m2
  36. [[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]]
  37. >>> m2[1,1,1]
  38. 7
  39. >>> m2.reshape(4, 3)
  40. [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
  41. Slice support:
  42. >>> m2[:, 1, 1]
  43. [3, 7, 11]
  44. Elementwise derivative:
  45. >>> from sympy.abc import x, y, z
  46. >>> m3 = Array([x**3, x*y, z])
  47. >>> m3.diff(x)
  48. [3*x**2, y, 0]
  49. >>> m3.diff(z)
  50. [0, 0, 1]
  51. Multiplication with other SymPy expressions is applied elementwisely:
  52. >>> (1+x)*m3
  53. [x**3*(x + 1), x*y*(x + 1), z*(x + 1)]
  54. To apply a function to each element of the N-dim array, use ``applyfunc``:
  55. >>> m3.applyfunc(lambda x: x/2)
  56. [x**3/2, x*y/2, z/2]
  57. N-dim arrays can be converted to nested lists by the ``tolist()`` method:
  58. >>> m2.tolist()
  59. [[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]]
  60. >>> isinstance(m2.tolist(), list)
  61. True
  62. If the rank is 2, it is possible to convert them to matrices with ``tomatrix()``:
  63. >>> m1.tomatrix()
  64. Matrix([
  65. [0, 1, 2, 3],
  66. [4, 5, 6, 7],
  67. [8, 9, 10, 11]])
  68. Products and contractions
  69. -------------------------
  70. Tensor product between arrays `A_{i_1,\ldots,i_n}` and `B_{j_1,\ldots,j_m}`
  71. creates the combined array `P = A \otimes B` defined as
  72. `P_{i_1,\ldots,i_n,j_1,\ldots,j_m} := A_{i_1,\ldots,i_n}\cdot B_{j_1,\ldots,j_m}.`
  73. It is available through ``tensorproduct(...)``:
  74. >>> from sympy import Array, tensorproduct
  75. >>> from sympy.abc import x,y,z,t
  76. >>> A = Array([x, y, z, t])
  77. >>> B = Array([1, 2, 3, 4])
  78. >>> tensorproduct(A, B)
  79. [[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]]
  80. Tensor product between a rank-1 array and a matrix creates a rank-3 array:
  81. >>> from sympy import eye
  82. >>> p1 = tensorproduct(A, eye(4))
  83. >>> p1
  84. [[[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]]]
  85. Now, to get back `A_0 \otimes \mathbf{1}` one can access `p_{0,m,n}` by slicing:
  86. >>> p1[0,:,:]
  87. [[x, 0, 0, 0], [0, x, 0, 0], [0, 0, x, 0], [0, 0, 0, x]]
  88. Tensor contraction sums over the specified axes, for example contracting
  89. positions `a` and `b` means
  90. `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}`
  91. Remember that Python indexing is zero starting, to contract the a-th and b-th
  92. axes it is therefore necessary to specify `a-1` and `b-1`
  93. >>> from sympy import tensorcontraction
  94. >>> C = Array([[x, y], [z, t]])
  95. The matrix trace is equivalent to the contraction of a rank-2 array:
  96. `A_{m,n} \implies \sum_k A_{k,k}`
  97. >>> tensorcontraction(C, (0, 1))
  98. t + x
  99. Matrix product is equivalent to a tensor product of two rank-2 arrays, followed
  100. by a contraction of the 2nd and 3rd axes (in Python indexing axes number 1, 2).
  101. `A_{m,n}\cdot B_{i,j} \implies \sum_k A_{m, k}\cdot B_{k, j}`
  102. >>> D = Array([[2, 1], [0, -1]])
  103. >>> tensorcontraction(tensorproduct(C, D), (1, 2))
  104. [[2*x, x - y], [2*z, -t + z]]
  105. One may verify that the matrix product is equivalent:
  106. >>> from sympy import Matrix
  107. >>> Matrix([[x, y], [z, t]])*Matrix([[2, 1], [0, -1]])
  108. Matrix([
  109. [2*x, x - y],
  110. [2*z, -t + z]])
  111. or equivalently
  112. >>> C.tomatrix()*D.tomatrix()
  113. Matrix([
  114. [2*x, x - y],
  115. [2*z, -t + z]])
  116. Diagonal operator
  117. -----------------
  118. The ``tensordiagonal`` function acts in a similar manner as ``tensorcontraction``,
  119. but the joined indices are not summed over, for example diagonalizing
  120. positions `a` and `b` means
  121. `A_{i_1,\ldots,i_a,\ldots,i_b,\ldots,i_n} \implies A_{i_1,\ldots,k,\ldots,k,\ldots,i_n}
  122. \implies \tilde{A}_{i_1,\ldots,i_{a-1},i_{a+1},\ldots,i_{b-1},i_{b+1},\ldots,i_n,k}`
  123. where `\tilde{A}` is the array equivalent to the diagonal of `A` at positions
  124. `a` and `b` moved to the last index slot.
  125. Compare the difference between contraction and diagonal operators:
  126. >>> from sympy import tensordiagonal
  127. >>> from sympy.abc import a, b, c, d
  128. >>> m = Matrix([[a, b], [c, d]])
  129. >>> tensorcontraction(m, [0, 1])
  130. a + d
  131. >>> tensordiagonal(m, [0, 1])
  132. [a, d]
  133. In short, no summation occurs with ``tensordiagonal``.
  134. Derivatives by array
  135. --------------------
  136. The usual derivative operation may be extended to support derivation with
  137. respect to arrays, provided that all elements in the that array are symbols or
  138. expressions suitable for derivations.
  139. The definition of a derivative by an array is as follows: given the array
  140. `A_{i_1, \ldots, i_N}` and the array `X_{j_1, \ldots, j_M}`
  141. the derivative of arrays will return a new array `B` defined by
  142. `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}}`
  143. The function ``derive_by_array`` performs such an operation:
  144. >>> from sympy import derive_by_array
  145. >>> from sympy.abc import x, y, z, t
  146. >>> from sympy import sin, exp
  147. With scalars, it behaves exactly as the ordinary derivative:
  148. >>> derive_by_array(sin(x*y), x)
  149. y*cos(x*y)
  150. Scalar derived by an array basis:
  151. >>> derive_by_array(sin(x*y), [x, y, z])
  152. [y*cos(x*y), x*cos(x*y), 0]
  153. Deriving array by an array basis: `B^{nm} := \frac{\partial A^m}{\partial x^n}`
  154. >>> basis = [x, y, z]
  155. >>> ax = derive_by_array([exp(x), sin(y*z), t], basis)
  156. >>> ax
  157. [[exp(x), 0, 0], [0, z*cos(y*z), 0], [0, y*cos(y*z), 0]]
  158. Contraction of the resulting array: `\sum_m \frac{\partial A^m}{\partial x^m}`
  159. >>> tensorcontraction(ax, (0, 1))
  160. z*cos(y*z) + exp(x)
  161. """
  162. from .dense_ndim_array import MutableDenseNDimArray, ImmutableDenseNDimArray, DenseNDimArray
  163. from .sparse_ndim_array import MutableSparseNDimArray, ImmutableSparseNDimArray, SparseNDimArray
  164. from .ndim_array import NDimArray, ArrayKind
  165. from .arrayop import tensorproduct, tensorcontraction, tensordiagonal, derive_by_array, permutedims
  166. from .array_comprehension import ArrayComprehension, ArrayComprehensionMap
  167. Array = ImmutableDenseNDimArray
  168. __all__ = [
  169. 'MutableDenseNDimArray', 'ImmutableDenseNDimArray', 'DenseNDimArray',
  170. 'MutableSparseNDimArray', 'ImmutableSparseNDimArray', 'SparseNDimArray',
  171. 'NDimArray', 'ArrayKind',
  172. 'tensorproduct', 'tensorcontraction', 'tensordiagonal', 'derive_by_array',
  173. 'permutedims', 'ArrayComprehension', 'ArrayComprehensionMap',
  174. 'Array',
  175. ]