modelparameters.sympy.tensor.array package¶
Submodules¶
modelparameters.sympy.tensor.array.arrayop module¶
- modelparameters.sympy.tensor.array.arrayop.derive_by_array(expr, dx)[source]¶
Derivative by arrays. Supports both arrays and scalars.
Given the array A_{i_1, ldots, i_N} and the array X_{j_1, ldots, j_M} this function will return a new array B defined by
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}}
Examples
>>> from ... import derive_by_array >>> from ...abc import x, y, z, t >>> from ... 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]]]
- modelparameters.sympy.tensor.array.arrayop.permutedims(expr, perm)[source]¶
Permutes the indices of an array.
Parameter specifies the permutation of the indices.
Examples
>>> from ...abc import x, y, z, t >>> from ... import sin >>> from ... 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]]
If the array is of second order,
transpose
can be used:>>> from ... import transpose >>> transpose(a) [[x, t], [y, sin(x)], [z, 0]]
Examples on higher dimensions:
>>> 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]]]
Permutation
objects are also allowed:>>> from ...combinatorics import Permutation >>> permutedims(b, Permutation([1, 2, 0])) [[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
- modelparameters.sympy.tensor.array.arrayop.tensorcontraction(array, *contraction_axes)[source]¶
Contraction of an array-like object on the specified axes.
Examples
>>> from ... import Array, tensorcontraction >>> from ... 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]
Matrix multiplication may be emulated with a proper combination of
tensorcontraction
andtensorproduct
>>> from ... import tensorproduct >>> from ...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]])
- modelparameters.sympy.tensor.array.arrayop.tensorproduct(*args)[source]¶
Tensor product among scalars or array-like objects.
Examples
>>> from ..array import tensorproduct, Array >>> from ...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]]]]
Applying this function on two matrices will result in a rank 4 array.
>>> from ... 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]]]]
modelparameters.sympy.tensor.array.dense_ndim_array module¶
- class modelparameters.sympy.tensor.array.dense_ndim_array.DenseNDimArray(*args, **kwargs)[source]¶
Bases:
NDimArray
- reshape(*newshape)[source]¶
Returns MutableDenseNDimArray instance with new shape. Elements number must be suitable to new shape. The only argument of method sets new shape.
Examples
>>> from ... import MutableDenseNDimArray >>> a = MutableDenseNDimArray([1, 2, 3, 4, 5, 6], (2, 3)) >>> a.shape (2, 3) >>> a [[1, 2, 3], [4, 5, 6]] >>> b = a.reshape(3, 2) >>> b.shape (3, 2) >>> b [[1, 2], [3, 4], [5, 6]]
- class modelparameters.sympy.tensor.array.dense_ndim_array.ImmutableDenseNDimArray(iterable=None, shape=None, **kwargs)[source]¶
Bases:
DenseNDimArray
,ImmutableNDimArray
- default_assumptions = {}¶
- class modelparameters.sympy.tensor.array.dense_ndim_array.MutableDenseNDimArray(iterable=None, shape=None, **kwargs)[source]¶
Bases:
DenseNDimArray
,MutableNDimArray
modelparameters.sympy.tensor.array.mutable_ndim_array module¶
modelparameters.sympy.tensor.array.ndim_array module¶
- class modelparameters.sympy.tensor.array.ndim_array.ImmutableNDimArray(*args, **kwargs)[source]¶
-
- default_assumptions = {}¶
- class modelparameters.sympy.tensor.array.ndim_array.NDimArray(*args, **kwargs)[source]¶
Bases:
object
Examples
Create an N-dim array of zeros:
>>> from ... import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(2, 3, 4) >>> a [[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]]
Create an N-dim array from a list;
>>> a = MutableDenseNDimArray([[2, 3], [4, 5]]) >>> a [[2, 3], [4, 5]]
>>> b = MutableDenseNDimArray([[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]]) >>> b [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]]
Create an N-dim array from a flat list with dimension shape:
>>> a = MutableDenseNDimArray([1, 2, 3, 4, 5, 6], (2, 3)) >>> a [[1, 2, 3], [4, 5, 6]]
Create an N-dim array from a matrix:
>>> from ... import Matrix >>> a = Matrix([[1,2],[3,4]]) >>> a Matrix([ [1, 2], [3, 4]]) >>> b = MutableDenseNDimArray(a) >>> b [[1, 2], [3, 4]]
Arithmetic operations on N-dim arrays
>>> a = MutableDenseNDimArray([1, 1, 1, 1], (2, 2)) >>> b = MutableDenseNDimArray([4, 4, 4, 4], (2, 2)) >>> c = a + b >>> c [[5, 5], [5, 5]] >>> a - b [[-3, -3], [-3, -3]]
- applyfunc(f)[source]¶
Apply a function to each element of the N-dim array.
Examples
>>> from ... import ImmutableDenseNDimArray >>> m = ImmutableDenseNDimArray([i*2+j for i in range(2) for j in range(2)], (2, 2)) >>> m [[0, 1], [2, 3]] >>> m.applyfunc(lambda i: 2*i) [[0, 2], [4, 6]]
- diff(*args)[source]¶
Calculate the derivative of each element in the array.
Examples
>>> from ... import ImmutableDenseNDimArray >>> from ...abc import x, y >>> M = ImmutableDenseNDimArray([[x, y], [1, x*y]]) >>> M.diff(x) [[1, 0], [0, y]]
- rank()[source]¶
Returns rank of array.
Examples
>>> from ... import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(3,4,5,6,3) >>> a.rank() 5
- property shape¶
Returns array shape (dimension).
Examples
>>> from ... import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(3, 3) >>> a.shape (3, 3)
modelparameters.sympy.tensor.array.sparse_ndim_array module¶
- class modelparameters.sympy.tensor.array.sparse_ndim_array.ImmutableSparseNDimArray(iterable=None, shape=None, **kwargs)[source]¶
Bases:
SparseNDimArray
,ImmutableNDimArray
- default_assumptions = {}¶
- class modelparameters.sympy.tensor.array.sparse_ndim_array.MutableSparseNDimArray(iterable=None, shape=None, **kwargs)[source]¶
Bases:
MutableNDimArray
,SparseNDimArray
- class modelparameters.sympy.tensor.array.sparse_ndim_array.SparseNDimArray(*args, **kwargs)[source]¶
Bases:
NDimArray
Module contents¶
N-dim array module for SymPy.
Four classes are provided to handle N-dim arrays, given by the combinations dense/sparse (i.e. whether to store all elements or only the non-zero ones in memory) and mutable/immutable (immutable classes are SymPy objects, but cannot change after they have been created).
Examples
The following examples show the usage of Array
. This is an abbreviation for
ImmutableDenseNDimArray
, that is an immutable and dense N-dim array, the
other classes are analogous. For mutable classes it is also possible to change
element values after the object has been constructed.
Array construction can detect the shape of nested lists and tuples:
>>> from ... 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 ...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
Otherwise one could pass a 1-dim array followed by a shape tuple:
>>> 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]]
Slice support:
>>> m2[:, 1, 1]
[3, 7, 11]
Elementwise derivative:
>>> from ...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]
Multiplication with other SymPy expressions is applied elementwisely:
>>> (1+x)*m3
[x**3*(x + 1), x*y*(x + 1), z*(x + 1)]
To apply a function to each element of the N-dim array, use applyfunc
:
>>> m3.applyfunc(lambda x: x/2)
[x**3/2, x*y/2, z/2]
N-dim arrays can be converted to nested lists by the tolist()
method:
>>> m2.tolist()
[[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]]
>>> isinstance(m2.tolist(), list)
True
If the rank is 2, it is possible to convert them to matrices with tomatrix()
:
>>> m1.tomatrix()
Matrix([
[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]])
Products and contractions¶
Tensor product between arrays A_{i_1,ldots,i_n} and B_{j_1,ldots,j_m} creates the combined array P = A otimes B defined as
P_{i_1,ldots,i_n,j_1,ldots,j_m} := A_{i_1,ldots,i_n}cdot B_{j_1,ldots,j_m}.
It is available through tensorproduct(...)
:
>>> from ... import Array, tensorproduct
>>> from ...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]]
Tensor product between a rank-1 array and a matrix creates a rank-3 array:
>>> from ... 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]]]
Now, to get back A_0 otimes mathbf{1} one can access p_{0,m,n} by slicing:
>>> p1[0,:,:]
[[x, 0, 0, 0], [0, x, 0, 0], [0, 0, x, 0], [0, 0, 0, x]]
Tensor contraction sums over the specified axes, for example contracting positions a and b means
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}
Remember that Python indexing is zero starting, to contract the a-th and b-th axes it is therefore necessary to specify a-1 and b-1
>>> from ... import tensorcontraction
>>> C = Array([[x, y], [z, t]])
The matrix trace is equivalent to the contraction of a rank-2 array:
A_{m,n} implies sum_k A_{k,k}
>>> tensorcontraction(C, (0, 1))
t + x
Matrix product is equivalent to a tensor product of two rank-2 arrays, followed by a contraction of the 2nd and 3rd axes (in Python indexing axes number 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]]
One may verify that the matrix product is equivalent:
>>> from ... import Matrix
>>> Matrix([[x, y], [z, t]])*Matrix([[2, 1], [0, -1]])
Matrix([
[2*x, x - y],
[2*z, -t + z]])
or equivalently
>>> C.tomatrix()*D.tomatrix()
Matrix([
[2*x, x - y],
[2*z, -t + z]])
Derivatives by array¶
The usual derivative operation may be extended to support derivation with respect to arrays, provided that all elements in the that array are symbols or expressions suitable for derivations.
The definition of a derivative by an array is as follows: given the array A_{i_1, ldots, i_N} and the array X_{j_1, ldots, j_M} the derivative of arrays will return a new array B defined by
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}}
The function derive_by_array
performs such an operation:
>>> from ... import derive_by_array
>>> from ...abc import x, y, z, t
>>> from ... import sin, exp
With scalars, it behaves exactly as the ordinary derivative:
>>> derive_by_array(sin(x*y), x)
y*cos(x*y)
Scalar derived by an array basis:
>>> derive_by_array(sin(x*y), [x, y, z])
[y*cos(x*y), x*cos(x*y), 0]
Deriving array by an array basis: 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]]
Contraction of the resulting array: sum_m frac{partial A^m}{partial x^m}
>>> tensorcontraction(ax, (0, 1))
z*cos(y*z) + exp(x)