Tensor¶
-
class
sympy.tensor.tensor._TensorManager[source]¶ Class to manage tensor properties.
Notes
Tensors belong to tensor commutation groups; each group has a label
comm; there are predefined labels:0tensors commuting with any other tensor1tensors anticommuting among themselves2tensors not commuting, apart with those withcomm=0Other groups can be defined using
set_comm; tensors in those groups commute with those withcomm=0; by default they do not commute with any other group.-
comm_symbols2i(i)[source]¶ get the commutation group number corresponding to
iican be a symbol or a number or a stringIf
iis not already defined its commutation group number is set.
-
get_comm(i, j)[source]¶ Return the commutation parameter for commutation group numbers
i, jsee
_TensorManager.set_comm
-
set_comm(i, j, c)[source]¶ set the commutation parameter
cfor commutation groupsi, j- Parameters
i, j : symbols representing commutation groups
c : group commutation number
Notes
i, jcan be symbols, strings or numbers, apart from0, 1and2which are reserved respectively for commuting, anticommuting tensors and tensors not commuting with any other group apart with the commuting tensors. For the remaining cases, use this method to set the commutation rules; by defaultc=None.The group commutation number
cis assigned in correspondence to the group commutation symbols; it can be0 commuting
1 anticommuting
None no commutation property
Examples
GandGHdo not commute with themselves and commute with each other; A is commuting.>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead, TensorManager >>> Lorentz = TensorIndexType('Lorentz') >>> i0,i1,i2,i3,i4 = tensor_indices('i0:5', Lorentz) >>> A = tensorhead('A', [Lorentz], [[1]]) >>> G = tensorhead('G', [Lorentz], [[1]], 'Gcomm') >>> GH = tensorhead('GH', [Lorentz], [[1]], 'GHcomm') >>> TensorManager.set_comm('Gcomm', 'GHcomm', 0) >>> (GH(i1)*G(i0)).canon_bp() G(i0)*GH(i1) >>> (G(i1)*G(i0)).canon_bp() G(i1)*G(i0) >>> (G(i1)*A(i0)).canon_bp() A(i0)*G(i1)
-
-
class
sympy.tensor.tensor.TensorIndexType(name, metric=False, dim=None, eps_dim=None, dummy_fmt=None)[source]¶ A TensorIndexType is characterized by its name and its metric.
- Parameters
name : name of the tensor type
metric : metric symmetry or metric object or
Nonedim : dimension, it can be a symbol or an integer or
Noneeps_dim : dimension of the epsilon tensor
dummy_fmt : name of the head of dummy indices
Notes
The
metricparameter can be:metric = Falsesymmetric metric (in Riemannian geometry)metric = Trueantisymmetric metric (for spinor calculus)metric = Nonethere is no metricmetriccan be an object havingnameandantisymattributes.If there is a metric the metric is used to raise and lower indices.
In the case of antisymmetric metric, the following raising and lowering conventions will be adopted:
psi(a) = g(a, b)*psi(-b); chi(-a) = chi(b)*g(-b, -a)g(-a, b) = delta(-a, b); g(b, -a) = -delta(a, -b)where
delta(-a, b) = delta(b, -a)is theKronecker delta(seeTensorIndexfor the conventions on indices).If there is no metric it is not possible to raise or lower indices; e.g. the index of the defining representation of
SU(N)is ‘covariant’ and the conjugate representation is ‘contravariant’; forN > 2they are linearly independent.eps_dimis by default equal todim, if the latter is an integer; else it can be assigned (for use in naive dimensional regularization); ifeps_dimis not an integerepsilonisNone.Examples
>>> from sympy.tensor.tensor import TensorIndexType >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> Lorentz.metric metric(Lorentz,Lorentz)
Examples with metric components data added, this means it is working on a fixed basis:
>>> Lorentz.data = [1, -1, -1, -1] >>> Lorentz TensorIndexType(Lorentz, 0) >>> Lorentz.data [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1]]
Attributes
namemetric_name(it is ‘metric’ or metric.name)
metric_antisymmetric(the metric tensor)
delta(
Kronecker delta)epsilon(the
Levi-Civita epsilontensor)dimdim_epsdummy_fmtdata(a property to add
ndarrayvalues, to work in a specified basis.)
-
class
sympy.tensor.tensor.TensorIndex(name, tensortype, is_up=True)[source]¶ Represents an abstract tensor index.
- Parameters
name : name of the index, or
Trueif you want it to be automatically assignedtensortype :
TensorIndexTypeof the indexis_up : flag for contravariant index
Notes
Tensor indices are contracted with the Einstein summation convention.
An index can be in contravariant or in covariant form; in the latter case it is represented prepending a
-to the index name.Dummy indices have a name with head given by
tensortype._dummy_fmtExamples
>>> from sympy.tensor.tensor import TensorIndexType, TensorIndex, TensorSymmetry, TensorType, get_symmetric_group_sgs >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> i = TensorIndex('i', Lorentz); i i >>> sym1 = TensorSymmetry(*get_symmetric_group_sgs(1)) >>> S1 = TensorType([Lorentz], sym1) >>> A, B = S1('A,B') >>> A(i)*B(-i) A(L_0)*B(-L_0)
If you want the index name to be automatically assigned, just put
Truein thenamefield, it will be generated using the reserved character_in front of its name, in order to avoid conflicts with possible existing indices:>>> i0 = TensorIndex(True, Lorentz) >>> i0 _i0 >>> i1 = TensorIndex(True, Lorentz) >>> i1 _i1 >>> A(i0)*B(-i1) A(_i0)*B(-_i1) >>> A(i0)*B(-i0) A(L_0)*B(-L_0)
Attributes
nametensortypeis_up
-
sympy.tensor.tensor.tensor_indices(s, typ)[source]¶ Returns list of tensor indices given their names and their types
- Parameters
s : string of comma separated names of indices
typ :
TensorIndexTypeof the indices
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz)
-
class
sympy.tensor.tensor.TensorSymmetry(*args, **kw_args)[source]¶ Monoterm symmetry of a tensor
- Parameters
bsgs : tuple
(base, sgs)BSGS of the symmetry of the tensor
Notes
A tensor can have an arbitrary monoterm symmetry provided by its BSGS. Multiterm symmetries, like the cyclic symmetry of the Riemann tensor, are not covered.
Examples
Define a symmetric tensor
>>> from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, TensorType, get_symmetric_group_sgs >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> sym2 = TensorSymmetry(get_symmetric_group_sgs(2)) >>> S2 = TensorType([Lorentz]*2, sym2) >>> V = S2('V')
Attributes
base(base of the BSGS)
generators(generators of the BSGS)
rank(rank of the tensor)
-
sympy.tensor.tensor.tensorsymmetry(*args)[source]¶ Return a
TensorSymmetryobject.One can represent a tensor with any monoterm slot symmetry group using a BSGS.
argscan be a BSGSargs[0]baseargs[1]sgsUsually tensors are in (direct products of) representations of the symmetric group;
argscan be a list of lists representing the shapes of Young tableauxNotes
For instance:
[[1]]vector[[1]*n]symmetric tensor of rankn[[n]]antisymmetric tensor of rankn[[2, 2]]monoterm slot symmetry of the Riemann tensor[[1],[1]]vector*vector[[2],[1],[1](antisymmetric tensor)*vector*vectorNotice that with the shape
[2, 2]we associate only the monoterm symmetries of the Riemann tensor; this is an abuse of notation, since the shape[2, 2]corresponds usually to the irreducible representation characterized by the monoterm symmetries and by the cyclic symmetry.Examples
Symmetric tensor using a Young tableau
>>> from sympy.tensor.tensor import TensorIndexType, TensorType, tensorsymmetry >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> sym2 = tensorsymmetry([1, 1]) >>> S2 = TensorType([Lorentz]*2, sym2) >>> V = S2('V')
Symmetric tensor using a
BSGS(base, strong generator set)>>> from sympy.tensor.tensor import get_symmetric_group_sgs >>> sym2 = tensorsymmetry(*get_symmetric_group_sgs(2)) >>> S2 = TensorType([Lorentz]*2, sym2) >>> V = S2('V')
-
class
sympy.tensor.tensor.TensorType(index_types, symmetry, **kw_args)[source]¶ Class of tensor types.
- Parameters
index_types : list of
TensorIndexTypeof the tensor indicessymmetry :
TensorSymmetryof the tensor
Examples
Define a symmetric tensor
>>> from sympy.tensor.tensor import TensorIndexType, tensorsymmetry, TensorType >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> sym2 = tensorsymmetry([1, 1]) >>> S2 = TensorType([Lorentz]*2, sym2) >>> V = S2('V')
Attributes
index_typessymmetrytypes(list of
TensorIndexTypewithout repetitions)
-
class
sympy.tensor.tensor.TensorHead(name, typ, comm=0, **kw_args)[source]¶ Tensor head of the tensor
- Parameters
name : name of the tensor
typ : list of TensorIndexType
comm : commutation group number
Notes
A
TensorHeadbelongs to a commutation group, defined by a symbol on numbercomm(see_TensorManager.set_comm); tensors in a commutation group have the same commutation properties; by defaultcommis0, the group of the commuting tensors.Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensorhead, TensorType >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> A = tensorhead('A', [Lorentz, Lorentz], [[1],[1]])
Examples with ndarray values, the components data assigned to the
TensorHeadobject are assumed to be in a fully-contravariant representation. In case it is necessary to assign components data which represents the values of a non-fully covariant tensor, see the other examples.>>> from sympy.tensor.tensor import tensor_indices, tensorhead >>> Lorentz.data = [1, -1, -1, -1] >>> i0, i1 = tensor_indices('i0:2', Lorentz) >>> A.data = [[j+2*i for j in range(4)] for i in range(4)]
in order to retrieve data, it is also necessary to specify abstract indices enclosed by round brackets, then numerical indices inside square brackets.
>>> A(i0, i1)[0, 0] 0 >>> A(i0, i1)[2, 3] == 3+2*2 True
Notice that square brackets create a valued tensor expression instance:
>>> A(i0, i1) A(i0, i1)
To view the data, just type:
>>> A.data [[0, 1, 2, 3], [2, 3, 4, 5], [4, 5, 6, 7], [6, 7, 8, 9]]
Turning to a tensor expression, covariant indices get the corresponding components data corrected by the metric:
>>> A(i0, -i1).data [[0, -1, -2, -3], [2, -3, -4, -5], [4, -5, -6, -7], [6, -7, -8, -9]]
>>> A(-i0, -i1).data [[0, -1, -2, -3], [-2, 3, 4, 5], [-4, 5, 6, 7], [-6, 7, 8, 9]]
while if all indices are contravariant, the
ndarrayremains the same>>> A(i0, i1).data [[0, 1, 2, 3], [2, 3, 4, 5], [4, 5, 6, 7], [6, 7, 8, 9]]
When all indices are contracted and components data are added to the tensor, accessing the data will return a scalar, no array object. In fact, arrays are dropped to scalars if they contain only one element.
>>> A(i0, -i0) A(L_0, -L_0) >>> A(i0, -i0).data -18
It is also possible to assign components data to an indexed tensor, i.e. a tensor with specified covariant and contravariant components. In this example, the covariant components data of the Electromagnetic tensor are injected into \(A\):
>>> from sympy import symbols >>> Ex, Ey, Ez, Bx, By, Bz = symbols('E_x E_y E_z B_x B_y B_z') >>> c = symbols('c', positive=True)
Let’s define \(F\), an antisymmetric tensor, we have to assign an antisymmetric matrix to it, because \([[2]]\) stands for the Young tableau representation of an antisymmetric set of two elements:
>>> F = tensorhead('A', [Lorentz, Lorentz], [[2]]) >>> F(-i0, -i1).data = [ ... [0, Ex/c, Ey/c, Ez/c], ... [-Ex/c, 0, -Bz, By], ... [-Ey/c, Bz, 0, -Bx], ... [-Ez/c, -By, Bx, 0]]
Now it is possible to retrieve the contravariant form of the Electromagnetic tensor:
>>> F(i0, i1).data [[0, -E_x/c, -E_y/c, -E_z/c], [E_x/c, 0, -B_z, B_y], [E_y/c, B_z, 0, -B_x], [E_z/c, -B_y, B_x, 0]]
and the mixed contravariant-covariant form:
>>> F(i0, -i1).data [[0, E_x/c, E_y/c, E_z/c], [E_x/c, 0, B_z, -B_y], [E_y/c, -B_z, 0, B_x], [E_z/c, B_y, -B_x, 0]]
To convert the darray to a SymPy matrix, just cast:
>>> F.data.tomatrix() Matrix([ [ 0, -E_x/c, -E_y/c, -E_z/c], [E_x/c, 0, -B_z, B_y], [E_y/c, B_z, 0, -B_x], [E_z/c, -B_y, B_x, 0]])
Still notice, in this last example, that accessing components data from a tensor without specifying the indices is equivalent to assume that all indices are contravariant.
It is also possible to store symbolic components data inside a tensor, for example, define a four-momentum-like tensor:
>>> from sympy import symbols >>> P = tensorhead('P', [Lorentz], [[1]]) >>> E, px, py, pz = symbols('E p_x p_y p_z', positive=True) >>> P.data = [E, px, py, pz]
The contravariant and covariant components are, respectively:
>>> P(i0).data [E, p_x, p_y, p_z] >>> P(-i0).data [E, -p_x, -p_y, -p_z]
The contraction of a 1-index tensor by itself is usually indicated by a power by two:
>>> P(i0)**2 E**2 - p_x**2 - p_y**2 - p_z**2
As the power by two is clearly identical to \(P_\mu P^\mu\), it is possible to simply contract the
TensorHeadobject, without specifying the indices>>> P**2 E**2 - p_x**2 - p_y**2 - p_z**2
Attributes
nameindex_typesranktypes( equal to
typ.types)symmetry(equal to
typ.symmetry)comm(commutation group)
-
class
sympy.tensor.tensor.TensExpr(*args)[source]¶ Abstract base class for tensor expressions
Notes
A tensor expression is an expression formed by tensors; currently the sums of tensors are distributed.
A
TensExprcan be aTensAddor aTensMul.TensAddobjects are put in canonical form using the Butler-Portugal algorithm for canonicalization under monoterm symmetries.TensMulobjects are formed by products of component tensors, and include a coefficient, which is a SymPy expression.In the internal representation contracted indices are represented by
(ipos1, ipos2, icomp1, icomp2), whereicomp1is the position of the component tensor with contravariant index,ipos1is the slot which the index occupies in that component tensor.Contracted indices are therefore nameless in the internal representation.
-
fun_eval(*index_tuples)[source]¶ Return a tensor with free indices substituted according to
index_tuplesindex_typeslist of tuples(old_index, new_index)Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) >>> t = A(i, k)*B(-k, -j); t A(i, L_0)*B(-L_0, -j) >>> t.fun_eval((i, k),(-j, l)) A(k, L_0)*B(-L_0, l)
-
get_matrix()[source]¶ Returns ndarray components data as a matrix, if components data are available and ndarray dimension does not exceed 2.
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensorsymmetry, TensorType >>> from sympy import ones >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> sym2 = tensorsymmetry([1]*2) >>> S2 = TensorType([Lorentz]*2, sym2) >>> A = S2('A')
The tensor
Ais symmetric in its indices, as can be deduced by the[1, 1]Young tableau when constructing \(sym2\). One has to be careful to assign symmetric component data toA, as the symmetry properties of data are currently not checked to be compatible with the defined tensor symmetry.>>> from sympy.tensor.tensor import tensor_indices, tensorhead >>> Lorentz.data = [1, -1, -1, -1] >>> i0, i1 = tensor_indices('i0:2', Lorentz) >>> A.data = [[j+i for j in range(4)] for i in range(4)] >>> A(i0, i1).get_matrix() Matrix([ [0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]])
It is possible to perform usual operation on matrices, such as the matrix multiplication:
>>> A(i0, i1).get_matrix()*ones(4, 1) Matrix([ [ 6], [10], [14], [18]])
-
-
class
sympy.tensor.tensor.TensAdd(*args, **kw_args)[source]¶ Sum of tensors
- Parameters
free_args : list of the free indices
Notes
Sum of more than one tensor are put automatically in canonical form.
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensorhead, tensor_indices >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> a, b = tensor_indices('a,b', Lorentz) >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) >>> t = p(a) + q(a); t p(a) + q(a) >>> t(b) p(b) + q(b)
Examples with components data added to the tensor expression:
>>> Lorentz.data = [1, -1, -1, -1] >>> a, b = tensor_indices('a, b', Lorentz) >>> p.data = [2, 3, -2, 7] >>> q.data = [2, 3, -2, 7] >>> t = p(a) + q(a); t p(a) + q(a) >>> t(b) p(b) + q(b)
The following are: 2**2 - 3**2 - 2**2 - 7**2 ==> -58
>>> (p(a)*p(-a)).data -58 >>> p(a)**2 -58
Attributes
args(tuple of addends)
rank(rank of the tensor)
free_args(list of the free indices in sorted order)
-
canon_bp()[source]¶ canonicalize using the Butler-Portugal algorithm for canonicalization under monoterm symmetries.
-
contract_metric(g)[source]¶ Raise or lower indices with the metric
g- Parameters
g : metric
contract_all : if True, eliminate all
gwhich are contracted
Notes
see the
TensorIndexTypedocstring for the contraction conventions
-
fun_eval(*index_tuples)[source]¶ Return a tensor with free indices substituted according to
index_tuples- Parameters
index_types : list of tuples
(old_index, new_index)
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) >>> t = A(i, k)*B(-k, -j) + A(i, -j) >>> t.fun_eval((i, k),(-j, l)) A(k, L_0)*B(l, -L_0) + A(k, l)
-
substitute_indices(*index_tuples)[source]¶ Return a tensor with free indices substituted according to
index_tuples- Parameters
index_types : list of tuples
(old_index, new_index)
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) >>> t = A(i, k)*B(-k, -j); t A(i, L_0)*B(-L_0, -j) >>> t.substitute_indices((i,j), (j, k)) A(j, L_0)*B(-L_0, -k)
-
class
sympy.tensor.tensor.TensMul(*args, **kw_args)[source]¶ Product of tensors
- Parameters
coeff : SymPy coefficient of the tensor
args
Notes
args[0]list ofTensorHeadof the component tensors.args[1]list of(ind, ipos, icomp)whereindis a free index,iposis the slot position ofindin theicomp-th component tensor.args[2]list of tuples representing dummy indices.(ipos1, ipos2, icomp1, icomp2)indicates that the contravariant dummy index is theipos1-th slot position in theicomp1-th component tensor; the corresponding covariant index is in theipos2slot position in theicomp2-th component tensor.Attributes
components(list of
TensorHeadof the component tensors)types(list of nonrepeated
TensorIndexType)free(list of
(ind, ipos, icomp), see Notes)dum(list of
(ipos1, ipos2, icomp1, icomp2), see Notes)ext_rank(rank of the tensor counting the dummy indices)
rank(rank of the tensor)
coeff(SymPy coefficient of the tensor)
free_args(list of the free indices in sorted order)
is_canon_bp(
Trueif the tensor in in canonical form)-
canon_bp()[source]¶ Canonicalize using the Butler-Portugal algorithm for canonicalization under monoterm symmetries.
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> A = tensorhead('A', [Lorentz]*2, [[2]]) >>> t = A(m0,-m1)*A(m1,-m0) >>> t.canon_bp() -A(L_0, L_1)*A(-L_0, -L_1) >>> t = A(m0,-m1)*A(m1,-m2)*A(m2,-m0) >>> t.canon_bp() 0
-
contract_metric(g)[source]¶ Raise or lower indices with the metric
g- Parameters
g : metric
Notes
see the
TensorIndexTypedocstring for the contraction conventionsExamples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> g = Lorentz.metric >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) >>> t = p(m0)*q(m1)*g(-m0, -m1) >>> t.canon_bp() metric(L_0, L_1)*p(-L_0)*q(-L_1) >>> t.contract_metric(g).canon_bp() p(L_0)*q(-L_0)
-
get_free_indices()[source]¶ Returns the list of free indices of the tensor
The indices are listed in the order in which they appear in the component tensors.
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> g = Lorentz.metric >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) >>> t = p(m1)*g(m0,m2) >>> t.get_free_indices() [m1, m0, m2] >>> t2 = p(m1)*g(-m1, m2) >>> t2.get_free_indices() [m2]
-
get_indices()[source]¶ Returns the list of indices of the tensor
The indices are listed in the order in which they appear in the component tensors. The dummy indices are given a name which does not collide with the names of the free indices.
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> g = Lorentz.metric >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) >>> t = p(m1)*g(m0,m2) >>> t.get_indices() [m1, m0, m2] >>> t2 = p(m1)*g(-m1, m2) >>> t2.get_indices() [L_0, -L_0, m2]
-
perm2tensor(g, is_canon_bp=False)[source]¶ Returns the tensor corresponding to the permutation
gFor further details, see the method in
TIDSwith the same name.
-
split()[source]¶ Returns a list of tensors, whose product is
selfDummy indices contracted among different tensor components become free indices with the same name as the one used to represent the dummy indices.
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz) >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) >>> t = A(a,b)*B(-b,c) >>> t A(a, L_0)*B(-L_0, c) >>> t.split() [A(a, L_0), B(-L_0, c)]
-
sympy.tensor.tensor.riemann_cyclic_replace(t_r)[source]¶ replace Riemann tensor with an equivalent expression
R(m,n,p,q) -> 2/3*R(m,n,p,q) - 1/3*R(m,q,n,p) + 1/3*R(m,p,n,q)
-
sympy.tensor.tensor.riemann_cyclic(t2)[source]¶ replace each Riemann tensor with an equivalent expression satisfying the cyclic identity.
This trick is discussed in the reference guide to Cadabra.
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead, riemann_cyclic >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) >>> R = tensorhead('R', [Lorentz]*4, [[2, 2]]) >>> t = R(i,j,k,l)*(R(-i,-j,-k,-l) - 2*R(-i,-k,-j,-l)) >>> riemann_cyclic(t) 0