Components as indexed sets of ring elements¶
The class Components
is a technical class to take in charge the
storage and manipulation of indexed elements of a commutative ring that
represent the components of some “mathematical entity” with respect to some
“frame”. Examples of entity/frame are vector/vector-space basis or
vector field/vector frame on some manifold. More generally, the components
can be those of a tensor on a free module or those of a tensor field on a
manifold. They can also be non-tensorial quantities, like connection
coefficients or structure coefficients of a vector frame.
The individual components are assumed to belong to a given commutative ring and are labelled by indices, which are tuples of integers. The following operations are implemented on components with respect to a given frame:
arithmetics (addition, subtraction, multiplication by a ring element)
handling of symmetries or antisymmetries on the indices
symmetrization and antisymmetrization
tensor product
contraction
Various subclasses of class Components
are
CompWithSym
for components with symmetries or antisymmetries w.r.t. index permutationsCompFullySym
for fully symmetric components w.r.t. index permutationsKroneckerDelta
for the Kronecker delta symbol
CompFullyAntiSym
for fully antisymmetric components w.r.t. index permutations
AUTHORS:
Eric Gourgoulhon, Michal Bejger (2014-2015): initial version
Joris Vankerschaver (2010): for the idea of storing only the non-zero components as dictionaries, whose keys are the component indices (implemented in the old class
DifferentialForm
; see Issue #24444)Marco Mancini (2015) : parallelization of some computations
EXAMPLES:
Set of components with 2 indices on a 3-dimensional vector space, the frame being some basis of the vector space:
sage: from sage.tensor.modules.comp import Components
sage: V = VectorSpace(QQ,3)
sage: basis = V.basis() ; basis
[
(1, 0, 0),
(0, 1, 0),
(0, 0, 1)
]
sage: c = Components(QQ, basis, 2) ; c
2-indices components w.r.t. [
(1, 0, 0),
(0, 1, 0),
(0, 0, 1)
]
>>> from sage.all import *
>>> from sage.tensor.modules.comp import Components
>>> V = VectorSpace(QQ,Integer(3))
>>> basis = V.basis() ; basis
[
(1, 0, 0),
(0, 1, 0),
(0, 0, 1)
]
>>> c = Components(QQ, basis, Integer(2)) ; c
2-indices components w.r.t. [
(1, 0, 0),
(0, 1, 0),
(0, 0, 1)
]
Actually, the frame can be any object that has some length, i.e. on which
the function len()
can be called:
sage: basis1 = V.gens() ; basis1
((1, 0, 0), (0, 1, 0), (0, 0, 1))
sage: c1 = Components(QQ, basis1, 2) ; c1
2-indices components w.r.t. ((1, 0, 0), (0, 1, 0), (0, 0, 1))
sage: basis2 = ['a', 'b' , 'c']
sage: c2 = Components(QQ, basis2, 2) ; c2
2-indices components w.r.t. ['a', 'b', 'c']
>>> from sage.all import *
>>> basis1 = V.gens() ; basis1
((1, 0, 0), (0, 1, 0), (0, 0, 1))
>>> c1 = Components(QQ, basis1, Integer(2)) ; c1
2-indices components w.r.t. ((1, 0, 0), (0, 1, 0), (0, 0, 1))
>>> basis2 = ['a', 'b' , 'c']
>>> c2 = Components(QQ, basis2, Integer(2)) ; c2
2-indices components w.r.t. ['a', 'b', 'c']
A just created set of components is initialized to zero:
sage: c.is_zero()
True
sage: c == 0
True
>>> from sage.all import *
>>> c.is_zero()
True
>>> c == Integer(0)
True
This can also be checked on the list of components, which is returned by
the operator [:]
:
sage: c[:]
[0 0 0]
[0 0 0]
[0 0 0]
>>> from sage.all import *
>>> c[:]
[0 0 0]
[0 0 0]
[0 0 0]
Individual components are accessed by providing their indices inside square brackets:
sage: c[1,2] = -3
sage: c[:]
[ 0 0 0]
[ 0 0 -3]
[ 0 0 0]
sage: v = Components(QQ, basis, 1)
sage: v[:]
[0, 0, 0]
sage: v[0]
0
sage: v[:] = (-1,3,2)
sage: v[:]
[-1, 3, 2]
sage: v[0]
-1
>>> from sage.all import *
>>> c[Integer(1),Integer(2)] = -Integer(3)
>>> c[:]
[ 0 0 0]
[ 0 0 -3]
[ 0 0 0]
>>> v = Components(QQ, basis, Integer(1))
>>> v[:]
[0, 0, 0]
>>> v[Integer(0)]
0
>>> v[:] = (-Integer(1),Integer(3),Integer(2))
>>> v[:]
[-1, 3, 2]
>>> v[Integer(0)]
-1
Sets of components with 2 indices can be converted into a matrix:
sage: matrix(c)
[ 0 0 0]
[ 0 0 -3]
[ 0 0 0]
sage: matrix(c).parent()
Full MatrixSpace of 3 by 3 dense matrices over Rational Field
>>> from sage.all import *
>>> matrix(c)
[ 0 0 0]
[ 0 0 -3]
[ 0 0 0]
>>> matrix(c).parent()
Full MatrixSpace of 3 by 3 dense matrices over Rational Field
By default, the indices range from \(0\) to \(n-1\), where \(n\) is the length
of the frame. This can be changed via the argument start_index
in
the Components
constructor:
sage: v1 = Components(QQ, basis, 1, start_index=1)
sage: v1[:]
[0, 0, 0]
sage: v1[0]
Traceback (most recent call last):
...
IndexError: index out of range: 0 not in [1, 3]
sage: v1[1]
0
sage: v1[:] = v[:] # list copy of all components
sage: v1[:]
[-1, 3, 2]
sage: v1[1], v1[2], v1[3]
(-1, 3, 2)
sage: v[0], v[1], v[2]
(-1, 3, 2)
>>> from sage.all import *
>>> v1 = Components(QQ, basis, Integer(1), start_index=Integer(1))
>>> v1[:]
[0, 0, 0]
>>> v1[Integer(0)]
Traceback (most recent call last):
...
IndexError: index out of range: 0 not in [1, 3]
>>> v1[Integer(1)]
0
>>> v1[:] = v[:] # list copy of all components
>>> v1[:]
[-1, 3, 2]
>>> v1[Integer(1)], v1[Integer(2)], v1[Integer(3)]
(-1, 3, 2)
>>> v[Integer(0)], v[Integer(1)], v[Integer(2)]
(-1, 3, 2)
If some formatter function or unbound method is provided via the argument
output_formatter
in the Components
constructor, it is used to
change the output of the access operator [...]
:
sage: a = Components(QQ, basis, 2, output_formatter=Rational.numerical_approx)
sage: a[1,2] = 1/3
sage: a[1,2]
0.333333333333333
>>> from sage.all import *
>>> a = Components(QQ, basis, Integer(2), output_formatter=Rational.numerical_approx)
>>> a[Integer(1),Integer(2)] = Integer(1)/Integer(3)
>>> a[Integer(1),Integer(2)]
0.333333333333333
The format can be passed to the formatter as the last argument of the
access operator [...]
:
sage: a[1,2,10] # here the format is 10, for 10 bits of precision
0.33
sage: a[1,2,100]
0.33333333333333333333333333333
>>> from sage.all import *
>>> a[Integer(1),Integer(2),Integer(10)] # here the format is 10, for 10 bits of precision
0.33
>>> a[Integer(1),Integer(2),Integer(100)]
0.33333333333333333333333333333
The raw (unformatted) components are then accessed by the double bracket operator:
sage: a[[1,2]]
1/3
>>> from sage.all import *
>>> a[[Integer(1),Integer(2)]]
1/3
For sets of components declared without any output formatter, there is no
difference between [...]
and [[...]]
:
sage: c[1,2] = 1/3
sage: c[1,2], c[[1,2]]
(1/3, 1/3)
>>> from sage.all import *
>>> c[Integer(1),Integer(2)] = Integer(1)/Integer(3)
>>> c[Integer(1),Integer(2)], c[[Integer(1),Integer(2)]]
(1/3, 1/3)
The formatter is also used for the complete list of components:
sage: a[:]
[0.000000000000000 0.000000000000000 0.000000000000000]
[0.000000000000000 0.000000000000000 0.333333333333333]
[0.000000000000000 0.000000000000000 0.000000000000000]
sage: a[:,10] # with a format different from the default one (53 bits)
[0.00 0.00 0.00]
[0.00 0.00 0.33]
[0.00 0.00 0.00]
>>> from sage.all import *
>>> a[:]
[0.000000000000000 0.000000000000000 0.000000000000000]
[0.000000000000000 0.000000000000000 0.333333333333333]
[0.000000000000000 0.000000000000000 0.000000000000000]
>>> a[:,Integer(10)] # with a format different from the default one (53 bits)
[0.00 0.00 0.00]
[0.00 0.00 0.33]
[0.00 0.00 0.00]
The complete list of components in raw form can be recovered by the double
bracket operator, replacing :
by slice(None)
(since a[[:]]
generates a Python syntax error):
sage: a[[slice(None)]]
[ 0 0 0]
[ 0 0 1/3]
[ 0 0 0]
>>> from sage.all import *
>>> a[[slice(None)]]
[ 0 0 0]
[ 0 0 1/3]
[ 0 0 0]
Another example of formatter: the Python built-in function str()
to generate string outputs:
sage: b = Components(QQ, V.basis(), 1, output_formatter=str)
sage: b[:] = (1, 0, -4)
sage: b[:]
['1', '0', '-4']
>>> from sage.all import *
>>> b = Components(QQ, V.basis(), Integer(1), output_formatter=str)
>>> b[:] = (Integer(1), Integer(0), -Integer(4))
>>> b[:]
['1', '0', '-4']
For such a formatter, 2-indices components are no longer displayed as a matrix:
sage: b = Components(QQ, basis, 2, output_formatter=str)
sage: b[0,1] = 1/3
sage: b[:]
[['0', '1/3', '0'], ['0', '0', '0'], ['0', '0', '0']]
>>> from sage.all import *
>>> b = Components(QQ, basis, Integer(2), output_formatter=str)
>>> b[Integer(0),Integer(1)] = Integer(1)/Integer(3)
>>> b[:]
[['0', '1/3', '0'], ['0', '0', '0'], ['0', '0', '0']]
But unformatted outputs still are:
sage: b[[slice(None)]]
[ 0 1/3 0]
[ 0 0 0]
[ 0 0 0]
>>> from sage.all import *
>>> b[[slice(None)]]
[ 0 1/3 0]
[ 0 0 0]
[ 0 0 0]
Internally, the components are stored as a dictionary (_comp
) whose
keys are the indices; only the nonzero components are stored:
sage: a[:]
[0.000000000000000 0.000000000000000 0.000000000000000]
[0.000000000000000 0.000000000000000 0.333333333333333]
[0.000000000000000 0.000000000000000 0.000000000000000]
sage: a._comp
{(1, 2): 1/3}
sage: v[:] = (-1, 0, 3)
sage: v._comp # random output order of the component dictionary
{(0,): -1, (2,): 3}
>>> from sage.all import *
>>> a[:]
[0.000000000000000 0.000000000000000 0.000000000000000]
[0.000000000000000 0.000000000000000 0.333333333333333]
[0.000000000000000 0.000000000000000 0.000000000000000]
>>> a._comp
{(1, 2): 1/3}
>>> v[:] = (-Integer(1), Integer(0), Integer(3))
>>> v._comp # random output order of the component dictionary
{(0,): -1, (2,): 3}
In case of symmetries, only non-redundant components are stored:
sage: from sage.tensor.modules.comp import CompFullyAntiSym
sage: c = CompFullyAntiSym(QQ, basis, 2)
sage: c[0,1] = 3
sage: c[:]
[ 0 3 0]
[-3 0 0]
[ 0 0 0]
sage: c._comp
{(0, 1): 3}
>>> from sage.all import *
>>> from sage.tensor.modules.comp import CompFullyAntiSym
>>> c = CompFullyAntiSym(QQ, basis, Integer(2))
>>> c[Integer(0),Integer(1)] = Integer(3)
>>> c[:]
[ 0 3 0]
[-3 0 0]
[ 0 0 0]
>>> c._comp
{(0, 1): 3}
- class sage.tensor.modules.comp.CompFullyAntiSym(ring, frame, nb_indices, start_index=0, output_formatter=None)[source]¶
Bases:
CompWithSym
Indexed set of ring elements forming some components with respect to a given “frame” that are fully antisymmetric with respect to any permutation of the indices.
The “frame” can be a basis of some vector space or a vector frame on some manifold (i.e. a field of bases). The stored quantities can be tensor components or non-tensorial quantities.
INPUT:
ring
– commutative ring in which each component takes its valueframe
– frame with respect to which the components are defined; whatever typeframe
is, it should have some method__len__()
implemented, so thatlen(frame)
returns the dimension, i.e. the size of a single index rangenb_indices
– number of indices labeling the componentsstart_index
– (default: 0) first value of a single index; accordingly a component index i must obeystart_index <= i <= start_index + dim - 1
, wheredim = len(frame)
.output_formatter
– (default:None
) function or unbound method called to format the output of the component access operator[...]
(method __getitem__);output_formatter
must take 1 or 2 arguments: the 1st argument must be an instance ofring
and the second one, if any, some format specification.
EXAMPLES:
Antisymmetric components with 2 indices on a 3-dimensional space:
sage: from sage.tensor.modules.comp import CompWithSym, CompFullyAntiSym sage: V = VectorSpace(QQ, 3) sage: c = CompFullyAntiSym(QQ, V.basis(), 2) sage: c[0,1], c[0,2], c[1,2] = 3, 1/2, -1 sage: c[:] # note that all components have been set according to the antisymmetry [ 0 3 1/2] [ -3 0 -1] [-1/2 1 0]
>>> from sage.all import * >>> from sage.tensor.modules.comp import CompWithSym, CompFullyAntiSym >>> V = VectorSpace(QQ, Integer(3)) >>> c = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> c[Integer(0),Integer(1)], c[Integer(0),Integer(2)], c[Integer(1),Integer(2)] = Integer(3), Integer(1)/Integer(2), -Integer(1) >>> c[:] # note that all components have been set according to the antisymmetry [ 0 3 1/2] [ -3 0 -1] [-1/2 1 0]
Internally, only non-redundant and nonzero components are stored:
sage: c._comp # random output order of the component dictionary {(0, 1): 3, (0, 2): 1/2, (1, 2): -1}
>>> from sage.all import * >>> c._comp # random output order of the component dictionary {(0, 1): 3, (0, 2): 1/2, (1, 2): -1}
Same thing, but with the starting index set to 1:
sage: c1 = CompFullyAntiSym(QQ, V.basis(), 2, start_index=1) sage: c1[1,2], c1[1,3], c1[2,3] = 3, 1/2, -1 sage: c1[:] [ 0 3 1/2] [ -3 0 -1] [-1/2 1 0]
>>> from sage.all import * >>> c1 = CompFullyAntiSym(QQ, V.basis(), Integer(2), start_index=Integer(1)) >>> c1[Integer(1),Integer(2)], c1[Integer(1),Integer(3)], c1[Integer(2),Integer(3)] = Integer(3), Integer(1)/Integer(2), -Integer(1) >>> c1[:] [ 0 3 1/2] [ -3 0 -1] [-1/2 1 0]
The values stored in
c
andc1
are equal:sage: c1[:] == c[:] True
>>> from sage.all import * >>> c1[:] == c[:] True
but not
c
andc1
, since their starting indices differ:sage: c1 == c False
>>> from sage.all import * >>> c1 == c False
Fully antisymmetric components with 3 indices on a 3-dimensional space:
sage: a = CompFullyAntiSym(QQ, V.basis(), 3) sage: a[0,1,2] = 3 # the only independent component in dimension 3 sage: a[:] [[[0, 0, 0], [0, 0, 3], [0, -3, 0]], [[0, 0, -3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [-3, 0, 0], [0, 0, 0]]]
>>> from sage.all import * >>> a = CompFullyAntiSym(QQ, V.basis(), Integer(3)) >>> a[Integer(0),Integer(1),Integer(2)] = Integer(3) # the only independent component in dimension 3 >>> a[:] [[[0, 0, 0], [0, 0, 3], [0, -3, 0]], [[0, 0, -3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [-3, 0, 0], [0, 0, 0]]]
Setting a nonzero value incompatible with the antisymmetry results in an error:
sage: a[0,1,0] = 4 Traceback (most recent call last): ... ValueError: by antisymmetry, the component cannot have a nonzero value for the indices (0, 1, 0) sage: a[0,1,0] = 0 # OK sage: a[2,0,1] = 3 # OK
>>> from sage.all import * >>> a[Integer(0),Integer(1),Integer(0)] = Integer(4) Traceback (most recent call last): ... ValueError: by antisymmetry, the component cannot have a nonzero value for the indices (0, 1, 0) >>> a[Integer(0),Integer(1),Integer(0)] = Integer(0) # OK >>> a[Integer(2),Integer(0),Integer(1)] = Integer(3) # OK
The full antisymmetry is preserved by the arithmetics:
sage: b = CompFullyAntiSym(QQ, V.basis(), 3) sage: b[0,1,2] = -4 sage: s = a + 2*b ; s Fully antisymmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: a[:], b[:], s[:] ([[[0, 0, 0], [0, 0, 3], [0, -3, 0]], [[0, 0, -3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [-3, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, -4], [0, 4, 0]], [[0, 0, 4], [0, 0, 0], [-4, 0, 0]], [[0, -4, 0], [4, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, -5], [0, 5, 0]], [[0, 0, 5], [0, 0, 0], [-5, 0, 0]], [[0, -5, 0], [5, 0, 0], [0, 0, 0]]])
>>> from sage.all import * >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(3)) >>> b[Integer(0),Integer(1),Integer(2)] = -Integer(4) >>> s = a + Integer(2)*b ; s Fully antisymmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> a[:], b[:], s[:] ([[[0, 0, 0], [0, 0, 3], [0, -3, 0]], [[0, 0, -3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [-3, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, -4], [0, 4, 0]], [[0, 0, 4], [0, 0, 0], [-4, 0, 0]], [[0, -4, 0], [4, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, -5], [0, 5, 0]], [[0, 0, 5], [0, 0, 0], [-5, 0, 0]], [[0, -5, 0], [5, 0, 0], [0, 0, 0]]])
It is lost if the added object is not fully antisymmetric:
sage: b1 = CompWithSym(QQ, V.basis(), 3, antisym=(0,1)) # b1 has only antisymmetry on index positions (0,1) sage: b1[0,1,2] = -4 sage: s = a + 2*b1 ; s # the result has the same symmetry as b1: 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) sage: a[:], b1[:], s[:] ([[[0, 0, 0], [0, 0, 3], [0, -3, 0]], [[0, 0, -3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [-3, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, -4], [0, 0, 0]], [[0, 0, 4], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, -5], [0, -3, 0]], [[0, 0, 5], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [-3, 0, 0], [0, 0, 0]]]) sage: s = 2*b1 + a ; s 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) sage: 2*b1 + a == a + 2*b1 True
>>> from sage.all import * >>> b1 = CompWithSym(QQ, V.basis(), Integer(3), antisym=(Integer(0),Integer(1))) # b1 has only antisymmetry on index positions (0,1) >>> b1[Integer(0),Integer(1),Integer(2)] = -Integer(4) >>> s = a + Integer(2)*b1 ; s # the result has the same symmetry as b1: 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) >>> a[:], b1[:], s[:] ([[[0, 0, 0], [0, 0, 3], [0, -3, 0]], [[0, 0, -3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [-3, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, -4], [0, 0, 0]], [[0, 0, 4], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, -5], [0, -3, 0]], [[0, 0, 5], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [-3, 0, 0], [0, 0, 0]]]) >>> s = Integer(2)*b1 + a ; s 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) >>> Integer(2)*b1 + a == a + Integer(2)*b1 True
- interior_product(other)[source]¶
Interior product with another set of fully antisymmetric components.
The interior product amounts to a contraction over all the \(p\) indices of
self
with the first \(p\) indices ofother
, assuming that the number \(q\) of indices ofother
obeys \(q\geq p\).Note
self.interior_product(other)
yields the same result asself.contract(0,..., p-1, other, 0,..., p-1)
(cf.contract()
), butinterior_product
is more efficient, the antisymmetry ofself
being not used to reduce the computation incontract()
.INPUT:
other
– fully antisymmetric components defined on the same frame asself
and with a number of indices at least equal to that ofself
OUTPUT:
base ring element (case \(p=q\)) or set of components (case \(p<q\)) resulting from the contraction over all the \(p\) indices of
self
with the first \(p\) indices ofother
EXAMPLES:
Interior product of a set of components
a
withp
indices with a set of componentsb
withq
indices on a 4-dimensional vector space.Case
p=2
andq=2
:sage: from sage.tensor.modules.comp import CompFullyAntiSym sage: V = VectorSpace(QQ, 4) sage: a = CompFullyAntiSym(QQ, V.basis(), 2) sage: a[0,1], a[0,2], a[0,3] = -2, 4, 3 sage: a[1,2], a[1,3], a[2,3] = 5, -3, 1 sage: b = CompFullyAntiSym(QQ, V.basis(), 2) sage: b[0,1], b[0,2], b[0,3] = 3, -4, 2 sage: b[1,2], b[1,3], b[2,3] = 2, 5, 1 sage: c = a.interior_product(b) sage: c -40 sage: c == a.contract(0, 1, b, 0, 1) True
>>> from sage.all import * >>> from sage.tensor.modules.comp import CompFullyAntiSym >>> V = VectorSpace(QQ, Integer(4)) >>> a = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> a[Integer(0),Integer(1)], a[Integer(0),Integer(2)], a[Integer(0),Integer(3)] = -Integer(2), Integer(4), Integer(3) >>> a[Integer(1),Integer(2)], a[Integer(1),Integer(3)], a[Integer(2),Integer(3)] = Integer(5), -Integer(3), Integer(1) >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> b[Integer(0),Integer(1)], b[Integer(0),Integer(2)], b[Integer(0),Integer(3)] = Integer(3), -Integer(4), Integer(2) >>> b[Integer(1),Integer(2)], b[Integer(1),Integer(3)], b[Integer(2),Integer(3)] = Integer(2), Integer(5), Integer(1) >>> c = a.interior_product(b) >>> c -40 >>> c == a.contract(Integer(0), Integer(1), b, Integer(0), Integer(1)) True
Case
p=2
andq=3
:sage: b = CompFullyAntiSym(QQ, V.basis(), 3) sage: b[0,1,2], b[0,1,3], b[0,2,3], b[1,2,3] = 3, -4, 2, 5 sage: c = a.interior_product(b) sage: c[:] [58, 10, 6, 82] sage: c == a.contract(0, 1, b, 0, 1) True
>>> from sage.all import * >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(3)) >>> b[Integer(0),Integer(1),Integer(2)], b[Integer(0),Integer(1),Integer(3)], b[Integer(0),Integer(2),Integer(3)], b[Integer(1),Integer(2),Integer(3)] = Integer(3), -Integer(4), Integer(2), Integer(5) >>> c = a.interior_product(b) >>> c[:] [58, 10, 6, 82] >>> c == a.contract(Integer(0), Integer(1), b, Integer(0), Integer(1)) True
Case
p=2
andq=4
:sage: b = CompFullyAntiSym(QQ, V.basis(), 4) sage: b[0,1,2,3] = 5 sage: c = a.interior_product(b) sage: c[:] [ 0 10 30 50] [-10 0 30 -40] [-30 -30 0 -20] [-50 40 20 0] sage: c == a.contract(0, 1, b, 0, 1) True
>>> from sage.all import * >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(4)) >>> b[Integer(0),Integer(1),Integer(2),Integer(3)] = Integer(5) >>> c = a.interior_product(b) >>> c[:] [ 0 10 30 50] [-10 0 30 -40] [-30 -30 0 -20] [-50 40 20 0] >>> c == a.contract(Integer(0), Integer(1), b, Integer(0), Integer(1)) True
Case
p=3
andq=3
:sage: a = CompFullyAntiSym(QQ, V.basis(), 3) sage: a[0,1,2], a[0,1,3], a[0,2,3], a[1,2,3] = 2, -1, 3, 5 sage: b = CompFullyAntiSym(QQ, V.basis(), 3) sage: b[0,1,2], b[0,1,3], b[0,2,3], b[1,2,3] = -2, 1, 4, 2 sage: c = a.interior_product(b) sage: c 102 sage: c == a.contract(0, 1, 2, b, 0, 1, 2) True
>>> from sage.all import * >>> a = CompFullyAntiSym(QQ, V.basis(), Integer(3)) >>> a[Integer(0),Integer(1),Integer(2)], a[Integer(0),Integer(1),Integer(3)], a[Integer(0),Integer(2),Integer(3)], a[Integer(1),Integer(2),Integer(3)] = Integer(2), -Integer(1), Integer(3), Integer(5) >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(3)) >>> b[Integer(0),Integer(1),Integer(2)], b[Integer(0),Integer(1),Integer(3)], b[Integer(0),Integer(2),Integer(3)], b[Integer(1),Integer(2),Integer(3)] = -Integer(2), Integer(1), Integer(4), Integer(2) >>> c = a.interior_product(b) >>> c 102 >>> c == a.contract(Integer(0), Integer(1), Integer(2), b, Integer(0), Integer(1), Integer(2)) True
Case
p=3
andq=4
:sage: b = CompFullyAntiSym(QQ, V.basis(), 4) sage: b[0,1,2,3] = 5 sage: c = a.interior_product(b) sage: c[:] [-150, 90, 30, 60] sage: c == a.contract(0, 1, 2, b, 0, 1, 2) True
>>> from sage.all import * >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(4)) >>> b[Integer(0),Integer(1),Integer(2),Integer(3)] = Integer(5) >>> c = a.interior_product(b) >>> c[:] [-150, 90, 30, 60] >>> c == a.contract(Integer(0), Integer(1), Integer(2), b, Integer(0), Integer(1), Integer(2)) True
Case
p=4
andq=4
:sage: a = CompFullyAntiSym(QQ, V.basis(), 4) sage: a[0,1,2,3] = 3 sage: c = a.interior_product(b) sage: c 360 sage: c == a.contract(0, 1, 2, 3, b, 0, 1, 2, 3) True
>>> from sage.all import * >>> a = CompFullyAntiSym(QQ, V.basis(), Integer(4)) >>> a[Integer(0),Integer(1),Integer(2),Integer(3)] = Integer(3) >>> c = a.interior_product(b) >>> c 360 >>> c == a.contract(Integer(0), Integer(1), Integer(2), Integer(3), b, Integer(0), Integer(1), Integer(2), Integer(3)) True
- class sage.tensor.modules.comp.CompFullySym(ring, frame, nb_indices, start_index=0, output_formatter=None)[source]¶
Bases:
CompWithSym
Indexed set of ring elements forming some components with respect to a given “frame” that are fully symmetric with respect to any permutation of the indices.
The “frame” can be a basis of some vector space or a vector frame on some manifold (i.e. a field of bases). The stored quantities can be tensor components or non-tensorial quantities.
INPUT:
ring
– commutative ring in which each component takes its valueframe
– frame with respect to which the components are defined; whatever typeframe
is, it should have some method__len__()
implemented, so thatlen(frame)
returns the dimension, i.e. the size of a single index rangenb_indices
– number of indices labeling the componentsstart_index
– (default: 0) first value of a single index; accordingly a component index i must obeystart_index <= i <= start_index + dim - 1
, wheredim = len(frame)
.output_formatter
– (default:None
) function or unbound method called to format the output of the component access operator[...]
(method __getitem__);output_formatter
must take 1 or 2 arguments: the 1st argument must be an instance ofring
and the second one, if any, some format specification.
EXAMPLES:
Symmetric components with 2 indices on a 3-dimensional space:
sage: from sage.tensor.modules.comp import CompFullySym, CompWithSym sage: V = VectorSpace(QQ, 3) sage: c = CompFullySym(QQ, V.basis(), 2) sage: c[0,0], c[0,1], c[1,2] = 1, -2, 3 sage: c[:] # note that c[1,0] and c[2,1] have been updated automatically (by symmetry) [ 1 -2 0] [-2 0 3] [ 0 3 0]
>>> from sage.all import * >>> from sage.tensor.modules.comp import CompFullySym, CompWithSym >>> V = VectorSpace(QQ, Integer(3)) >>> c = CompFullySym(QQ, V.basis(), Integer(2)) >>> c[Integer(0),Integer(0)], c[Integer(0),Integer(1)], c[Integer(1),Integer(2)] = Integer(1), -Integer(2), Integer(3) >>> c[:] # note that c[1,0] and c[2,1] have been updated automatically (by symmetry) [ 1 -2 0] [-2 0 3] [ 0 3 0]
Internally, only non-redundant and nonzero components are stored:
sage: c._comp # random output order of the component dictionary {(0, 0): 1, (0, 1): -2, (1, 2): 3}
>>> from sage.all import * >>> c._comp # random output order of the component dictionary {(0, 0): 1, (0, 1): -2, (1, 2): 3}
Same thing, but with the starting index set to 1:
sage: c1 = CompFullySym(QQ, V.basis(), 2, start_index=1) sage: c1[1,1], c1[1,2], c1[2,3] = 1, -2, 3 sage: c1[:] [ 1 -2 0] [-2 0 3] [ 0 3 0]
>>> from sage.all import * >>> c1 = CompFullySym(QQ, V.basis(), Integer(2), start_index=Integer(1)) >>> c1[Integer(1),Integer(1)], c1[Integer(1),Integer(2)], c1[Integer(2),Integer(3)] = Integer(1), -Integer(2), Integer(3) >>> c1[:] [ 1 -2 0] [-2 0 3] [ 0 3 0]
The values stored in
c
andc1
are equal:sage: c1[:] == c[:] True
>>> from sage.all import * >>> c1[:] == c[:] True
but not
c
andc1
, since their starting indices differ:sage: c1 == c False
>>> from sage.all import * >>> c1 == c False
Fully symmetric components with 3 indices on a 3-dimensional space:
sage: a = CompFullySym(QQ, V.basis(), 3) sage: a[0,1,2] = 3 sage: a[:] [[[0, 0, 0], [0, 0, 3], [0, 3, 0]], [[0, 0, 3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [3, 0, 0], [0, 0, 0]]] sage: a[0,1,0] = 4 sage: a[:] [[[0, 4, 0], [4, 0, 3], [0, 3, 0]], [[4, 0, 3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [3, 0, 0], [0, 0, 0]]]
>>> from sage.all import * >>> a = CompFullySym(QQ, V.basis(), Integer(3)) >>> a[Integer(0),Integer(1),Integer(2)] = Integer(3) >>> a[:] [[[0, 0, 0], [0, 0, 3], [0, 3, 0]], [[0, 0, 3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [3, 0, 0], [0, 0, 0]]] >>> a[Integer(0),Integer(1),Integer(0)] = Integer(4) >>> a[:] [[[0, 4, 0], [4, 0, 3], [0, 3, 0]], [[4, 0, 3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [3, 0, 0], [0, 0, 0]]]
The full symmetry is preserved by the arithmetics:
sage: b = CompFullySym(QQ, V.basis(), 3) sage: b[0,0,0], b[0,1,0], b[1,0,2], b[1,2,2] = -2, 3, 1, -5 sage: s = a + 2*b ; s Fully symmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: a[:], b[:], s[:] ([[[0, 4, 0], [4, 0, 3], [0, 3, 0]], [[4, 0, 3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [3, 0, 0], [0, 0, 0]]], [[[-2, 3, 0], [3, 0, 1], [0, 1, 0]], [[3, 0, 1], [0, 0, 0], [1, 0, -5]], [[0, 1, 0], [1, 0, -5], [0, -5, 0]]], [[[-4, 10, 0], [10, 0, 5], [0, 5, 0]], [[10, 0, 5], [0, 0, 0], [5, 0, -10]], [[0, 5, 0], [5, 0, -10], [0, -10, 0]]])
>>> from sage.all import * >>> b = CompFullySym(QQ, V.basis(), Integer(3)) >>> b[Integer(0),Integer(0),Integer(0)], b[Integer(0),Integer(1),Integer(0)], b[Integer(1),Integer(0),Integer(2)], b[Integer(1),Integer(2),Integer(2)] = -Integer(2), Integer(3), Integer(1), -Integer(5) >>> s = a + Integer(2)*b ; s Fully symmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> a[:], b[:], s[:] ([[[0, 4, 0], [4, 0, 3], [0, 3, 0]], [[4, 0, 3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [3, 0, 0], [0, 0, 0]]], [[[-2, 3, 0], [3, 0, 1], [0, 1, 0]], [[3, 0, 1], [0, 0, 0], [1, 0, -5]], [[0, 1, 0], [1, 0, -5], [0, -5, 0]]], [[[-4, 10, 0], [10, 0, 5], [0, 5, 0]], [[10, 0, 5], [0, 0, 0], [5, 0, -10]], [[0, 5, 0], [5, 0, -10], [0, -10, 0]]])
It is lost if the added object is not fully symmetric:
sage: b1 = CompWithSym(QQ, V.basis(), 3, sym=(0,1)) # b1 has only symmetry on index positions (0,1) sage: b1[0,0,0], b1[0,1,0], b1[1,0,2], b1[1,2,2] = -2, 3, 1, -5 sage: s = a + 2*b1 ; s # the result has the same symmetry as b1: 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) sage: a[:], b1[:], s[:] ([[[0, 4, 0], [4, 0, 3], [0, 3, 0]], [[4, 0, 3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [3, 0, 0], [0, 0, 0]]], [[[-2, 0, 0], [3, 0, 1], [0, 0, 0]], [[3, 0, 1], [0, 0, 0], [0, 0, -5]], [[0, 0, 0], [0, 0, -5], [0, 0, 0]]], [[[-4, 4, 0], [10, 0, 5], [0, 3, 0]], [[10, 0, 5], [0, 0, 0], [3, 0, -10]], [[0, 3, 0], [3, 0, -10], [0, 0, 0]]]) sage: s = 2*b1 + a ; s 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) sage: 2*b1 + a == a + 2*b1 True
>>> from sage.all import * >>> b1 = CompWithSym(QQ, V.basis(), Integer(3), sym=(Integer(0),Integer(1))) # b1 has only symmetry on index positions (0,1) >>> b1[Integer(0),Integer(0),Integer(0)], b1[Integer(0),Integer(1),Integer(0)], b1[Integer(1),Integer(0),Integer(2)], b1[Integer(1),Integer(2),Integer(2)] = -Integer(2), Integer(3), Integer(1), -Integer(5) >>> s = a + Integer(2)*b1 ; s # the result has the same symmetry as b1: 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) >>> a[:], b1[:], s[:] ([[[0, 4, 0], [4, 0, 3], [0, 3, 0]], [[4, 0, 3], [0, 0, 0], [3, 0, 0]], [[0, 3, 0], [3, 0, 0], [0, 0, 0]]], [[[-2, 0, 0], [3, 0, 1], [0, 0, 0]], [[3, 0, 1], [0, 0, 0], [0, 0, -5]], [[0, 0, 0], [0, 0, -5], [0, 0, 0]]], [[[-4, 4, 0], [10, 0, 5], [0, 3, 0]], [[10, 0, 5], [0, 0, 0], [3, 0, -10]], [[0, 3, 0], [3, 0, -10], [0, 0, 0]]]) >>> s = Integer(2)*b1 + a ; s 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) >>> Integer(2)*b1 + a == a + Integer(2)*b1 True
- class sage.tensor.modules.comp.CompWithSym(ring, frame, nb_indices, start_index=0, output_formatter=None, sym=None, antisym=None)[source]¶
Bases:
Components
Indexed set of ring elements forming some components with respect to a given “frame”, with symmetries or antisymmetries regarding permutations of the indices.
The “frame” can be a basis of some vector space or a vector frame on some manifold (i.e. a field of bases). The stored quantities can be tensor components or non-tensorial quantities, such as connection coefficients or structure coefficients.
Subclasses of
CompWithSym
areCompFullySym
for fully symmetric components.CompFullyAntiSym
for fully antisymmetric components.
INPUT:
ring
– commutative ring in which each component takes its valueframe
– frame with respect to which the components are defined; whatever typeframe
is, it should have some method__len__()
implemented, so thatlen(frame)
returns the dimension, i.e. the size of a single index rangenb_indices
– number of indices labeling the componentsstart_index
– (default: 0) first value of a single index; accordingly a component index i must obeystart_index <= i <= start_index + dim - 1
, wheredim = len(frame)
.output_formatter
– (default:None
) function or unbound method called to format the output of the component access operator[...]
(method __getitem__);output_formatter
must take 1 or 2 arguments: the 1st argument must be an instance ofring
and the second one, if any, some format specification.sym
– (default:None
) a symmetry or a list of symmetries among the indices: each symmetry is described by a tuple containing the positions of the involved indices, with the conventionposition=0
for the first slot; for instance:sym = (0, 1)
for a symmetry between the 1st and 2nd indicessym = [(0,2), (1,3,4)]
for a symmetry between the 1st and 3rd indices and a symmetry between the 2nd, 4th and 5th indices.
antisym
– (default:None
) antisymmetry or list of antisymmetries among the indices, with the same convention as forsym
EXAMPLES:
Symmetric components with 2 indices:
sage: from sage.tensor.modules.comp import Components, CompWithSym sage: V = VectorSpace(QQ,3) sage: c = CompWithSym(QQ, V.basis(), 2, sym=(0,1)) # for demonstration only: it is preferable to use CompFullySym in this case sage: c[0,1] = 3 sage: c[:] # note that c[1,0] has been set automatically [0 3 0] [3 0 0] [0 0 0]
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components, CompWithSym >>> V = VectorSpace(QQ,Integer(3)) >>> c = CompWithSym(QQ, V.basis(), Integer(2), sym=(Integer(0),Integer(1))) # for demonstration only: it is preferable to use CompFullySym in this case >>> c[Integer(0),Integer(1)] = Integer(3) >>> c[:] # note that c[1,0] has been set automatically [0 3 0] [3 0 0] [0 0 0]
Antisymmetric components with 2 indices:
sage: c = CompWithSym(QQ, V.basis(), 2, antisym=(0,1)) # for demonstration only: it is preferable to use CompFullyAntiSym in this case sage: c[0,1] = 3 sage: c[:] # note that c[1,0] has been set automatically [ 0 3 0] [-3 0 0] [ 0 0 0]
>>> from sage.all import * >>> c = CompWithSym(QQ, V.basis(), Integer(2), antisym=(Integer(0),Integer(1))) # for demonstration only: it is preferable to use CompFullyAntiSym in this case >>> c[Integer(0),Integer(1)] = Integer(3) >>> c[:] # note that c[1,0] has been set automatically [ 0 3 0] [-3 0 0] [ 0 0 0]
Internally, only non-redundant components are stored:
sage: c._comp {(0, 1): 3}
>>> from sage.all import * >>> c._comp {(0, 1): 3}
Components with 6 indices, symmetric among 3 indices (at position \((0, 1, 5)\)) and antisymmetric among 2 indices (at position \((2, 4)\)):
sage: c = CompWithSym(QQ, V.basis(), 6, sym=(0,1,5), antisym=(2,4)) sage: c[0,1,2,0,1,2] = 3 sage: c[1,0,2,0,1,2] # symmetry between indices in position 0 and 1 3 sage: c[2,1,2,0,1,0] # symmetry between indices in position 0 and 5 3 sage: c[0,2,2,0,1,1] # symmetry between indices in position 1 and 5 3 sage: c[0,1,1,0,2,2] # antisymmetry between indices in position 2 and 4 -3
>>> from sage.all import * >>> c = CompWithSym(QQ, V.basis(), Integer(6), sym=(Integer(0),Integer(1),Integer(5)), antisym=(Integer(2),Integer(4))) >>> c[Integer(0),Integer(1),Integer(2),Integer(0),Integer(1),Integer(2)] = Integer(3) >>> c[Integer(1),Integer(0),Integer(2),Integer(0),Integer(1),Integer(2)] # symmetry between indices in position 0 and 1 3 >>> c[Integer(2),Integer(1),Integer(2),Integer(0),Integer(1),Integer(0)] # symmetry between indices in position 0 and 5 3 >>> c[Integer(0),Integer(2),Integer(2),Integer(0),Integer(1),Integer(1)] # symmetry between indices in position 1 and 5 3 >>> c[Integer(0),Integer(1),Integer(1),Integer(0),Integer(2),Integer(2)] # antisymmetry between indices in position 2 and 4 -3
Components with 4 indices, antisymmetric with respect to the first pair of indices as well as with the second pair of indices:
sage: c = CompWithSym(QQ, V.basis(), 4, antisym=[(0,1),(2,3)]) sage: c[0,1,0,1] = 3 sage: c[1,0,0,1] # antisymmetry on the first pair of indices -3 sage: c[0,1,1,0] # antisymmetry on the second pair of indices -3 sage: c[1,0,1,0] # consequence of the above 3
>>> from sage.all import * >>> c = CompWithSym(QQ, V.basis(), Integer(4), antisym=[(Integer(0),Integer(1)),(Integer(2),Integer(3))]) >>> c[Integer(0),Integer(1),Integer(0),Integer(1)] = Integer(3) >>> c[Integer(1),Integer(0),Integer(0),Integer(1)] # antisymmetry on the first pair of indices -3 >>> c[Integer(0),Integer(1),Integer(1),Integer(0)] # antisymmetry on the second pair of indices -3 >>> c[Integer(1),Integer(0),Integer(1),Integer(0)] # consequence of the above 3
ARITHMETIC EXAMPLES
Addition of a symmetric set of components with a non-symmetric one: the symmetry is lost:
sage: V = VectorSpace(QQ, 3) sage: a = Components(QQ, V.basis(), 2) sage: a[:] = [[1,-2,3], [4,5,-6], [-7,8,9]] sage: b = CompWithSym(QQ, V.basis(), 2, sym=(0,1)) # for demonstration only: it is preferable to declare b = CompFullySym(QQ, V.basis(), 2) sage: b[0,0], b[0,1], b[0,2] = 1, 2, 3 sage: b[1,1], b[1,2] = 5, 7 sage: b[2,2] = 11 sage: s = a + b ; s 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: a[:], b[:], s[:] ( [ 1 -2 3] [ 1 2 3] [ 2 0 6] [ 4 5 -6] [ 2 5 7] [ 6 10 1] [-7 8 9], [ 3 7 11], [-4 15 20] ) sage: a + b == b + a True
>>> from sage.all import * >>> V = VectorSpace(QQ, Integer(3)) >>> a = Components(QQ, V.basis(), Integer(2)) >>> a[:] = [[Integer(1),-Integer(2),Integer(3)], [Integer(4),Integer(5),-Integer(6)], [-Integer(7),Integer(8),Integer(9)]] >>> b = CompWithSym(QQ, V.basis(), Integer(2), sym=(Integer(0),Integer(1))) # for demonstration only: it is preferable to declare b = CompFullySym(QQ, V.basis(), 2) >>> b[Integer(0),Integer(0)], b[Integer(0),Integer(1)], b[Integer(0),Integer(2)] = Integer(1), Integer(2), Integer(3) >>> b[Integer(1),Integer(1)], b[Integer(1),Integer(2)] = Integer(5), Integer(7) >>> b[Integer(2),Integer(2)] = Integer(11) >>> s = a + b ; s 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> a[:], b[:], s[:] ( [ 1 -2 3] [ 1 2 3] [ 2 0 6] [ 4 5 -6] [ 2 5 7] [ 6 10 1] [-7 8 9], [ 3 7 11], [-4 15 20] ) >>> a + b == b + a True
Addition of two symmetric set of components: the symmetry is preserved:
sage: c = CompWithSym(QQ, V.basis(), 2, sym=(0,1)) # for demonstration only: it is preferable to declare c = CompFullySym(QQ, V.basis(), 2) sage: c[0,0], c[0,1], c[0,2] = -4, 7, -8 sage: c[1,1], c[1,2] = 2, -4 sage: c[2,2] = 2 sage: s = b + c ; s 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) sage: b[:], c[:], s[:] ( [ 1 2 3] [-4 7 -8] [-3 9 -5] [ 2 5 7] [ 7 2 -4] [ 9 7 3] [ 3 7 11], [-8 -4 2], [-5 3 13] ) sage: b + c == c + b True
>>> from sage.all import * >>> c = CompWithSym(QQ, V.basis(), Integer(2), sym=(Integer(0),Integer(1))) # for demonstration only: it is preferable to declare c = CompFullySym(QQ, V.basis(), 2) >>> c[Integer(0),Integer(0)], c[Integer(0),Integer(1)], c[Integer(0),Integer(2)] = -Integer(4), Integer(7), -Integer(8) >>> c[Integer(1),Integer(1)], c[Integer(1),Integer(2)] = Integer(2), -Integer(4) >>> c[Integer(2),Integer(2)] = Integer(2) >>> s = b + c ; s 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) >>> b[:], c[:], s[:] ( [ 1 2 3] [-4 7 -8] [-3 9 -5] [ 2 5 7] [ 7 2 -4] [ 9 7 3] [ 3 7 11], [-8 -4 2], [-5 3 13] ) >>> b + c == c + b True
Check of the addition with counterparts not declared symmetric:
sage: bn = Components(QQ, V.basis(), 2) sage: bn[:] = b[:] sage: bn == b True sage: cn = Components(QQ, V.basis(), 2) sage: cn[:] = c[:] sage: cn == c True sage: bn + cn == b + c True
>>> from sage.all import * >>> bn = Components(QQ, V.basis(), Integer(2)) >>> bn[:] = b[:] >>> bn == b True >>> cn = Components(QQ, V.basis(), Integer(2)) >>> cn[:] = c[:] >>> cn == c True >>> bn + cn == b + c True
Addition of an antisymmetric set of components with a non-symmetric one: the antisymmetry is lost:
sage: d = CompWithSym(QQ, V.basis(), 2, antisym=(0,1)) # for demonstration only: it is preferable to declare d = CompFullyAntiSym(QQ, V.basis(), 2) sage: d[0,1], d[0,2], d[1,2] = 4, -1, 3 sage: s = a + d ; s 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: a[:], d[:], s[:] ( [ 1 -2 3] [ 0 4 -1] [ 1 2 2] [ 4 5 -6] [-4 0 3] [ 0 5 -3] [-7 8 9], [ 1 -3 0], [-6 5 9] ) sage: d + a == a + d True
>>> from sage.all import * >>> d = CompWithSym(QQ, V.basis(), Integer(2), antisym=(Integer(0),Integer(1))) # for demonstration only: it is preferable to declare d = CompFullyAntiSym(QQ, V.basis(), 2) >>> d[Integer(0),Integer(1)], d[Integer(0),Integer(2)], d[Integer(1),Integer(2)] = Integer(4), -Integer(1), Integer(3) >>> s = a + d ; s 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> a[:], d[:], s[:] ( [ 1 -2 3] [ 0 4 -1] [ 1 2 2] [ 4 5 -6] [-4 0 3] [ 0 5 -3] [-7 8 9], [ 1 -3 0], [-6 5 9] ) >>> d + a == a + d True
Addition of two antisymmetric set of components: the antisymmetry is preserved:
sage: e = CompWithSym(QQ, V.basis(), 2, antisym=(0,1)) # for demonstration only: it is preferable to declare e = CompFullyAntiSym(QQ, V.basis(), 2) sage: e[0,1], e[0,2], e[1,2] = 2, 3, -1 sage: s = d + e ; s 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) sage: d[:], e[:], s[:] ( [ 0 4 -1] [ 0 2 3] [ 0 6 2] [-4 0 3] [-2 0 -1] [-6 0 2] [ 1 -3 0], [-3 1 0], [-2 -2 0] ) sage: e + d == d + e True
>>> from sage.all import * >>> e = CompWithSym(QQ, V.basis(), Integer(2), antisym=(Integer(0),Integer(1))) # for demonstration only: it is preferable to declare e = CompFullyAntiSym(QQ, V.basis(), 2) >>> e[Integer(0),Integer(1)], e[Integer(0),Integer(2)], e[Integer(1),Integer(2)] = Integer(2), Integer(3), -Integer(1) >>> s = d + e ; s 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) >>> d[:], e[:], s[:] ( [ 0 4 -1] [ 0 2 3] [ 0 6 2] [-4 0 3] [-2 0 -1] [-6 0 2] [ 1 -3 0], [-3 1 0], [-2 -2 0] ) >>> e + d == d + e True
- antisymmetrize(*pos)[source]¶
Antisymmetrization over the given index positions.
INPUT:
pos
– list of index positions involved in the antisymmetrization (with the conventionposition=0
for the first slot); if none, the antisymmetrization is performed over all the indices
OUTPUT:
an instance of
CompWithSym
describing the antisymmetrized components
EXAMPLES:
Antisymmetrization of 3-indices components on a 3-dimensional space:
sage: from sage.tensor.modules.comp import Components, CompWithSym, \ ....: CompFullySym, CompFullyAntiSym sage: V = VectorSpace(QQ, 3) sage: a = Components(QQ, V.basis(), 1) sage: a[:] = (-2,1,3) sage: b = CompFullyAntiSym(QQ, V.basis(), 2) sage: b[0,1], b[0,2], b[1,2] = (4,1,2) sage: c = a*b ; c # tensor product of a by b 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2) sage: s = c.antisymmetrize() ; s Fully antisymmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: c[:], s[:] ([[[0, -8, -2], [8, 0, -4], [2, 4, 0]], [[0, 4, 1], [-4, 0, 2], [-1, -2, 0]], [[0, 12, 3], [-12, 0, 6], [-3, -6, 0]]], [[[0, 0, 0], [0, 0, 7/3], [0, -7/3, 0]], [[0, 0, -7/3], [0, 0, 0], [7/3, 0, 0]], [[0, 7/3, 0], [-7/3, 0, 0], [0, 0, 0]]])
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components, CompWithSym, CompFullySym, CompFullyAntiSym >>> V = VectorSpace(QQ, Integer(3)) >>> a = Components(QQ, V.basis(), Integer(1)) >>> a[:] = (-Integer(2),Integer(1),Integer(3)) >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> b[Integer(0),Integer(1)], b[Integer(0),Integer(2)], b[Integer(1),Integer(2)] = (Integer(4),Integer(1),Integer(2)) >>> c = a*b ; c # tensor product of a by b 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2) >>> s = c.antisymmetrize() ; s Fully antisymmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> c[:], s[:] ([[[0, -8, -2], [8, 0, -4], [2, 4, 0]], [[0, 4, 1], [-4, 0, 2], [-1, -2, 0]], [[0, 12, 3], [-12, 0, 6], [-3, -6, 0]]], [[[0, 0, 0], [0, 0, 7/3], [0, -7/3, 0]], [[0, 0, -7/3], [0, 0, 0], [7/3, 0, 0]], [[0, 7/3, 0], [-7/3, 0, 0], [0, 0, 0]]])
Check of the antisymmetrization:
sage: all(s[i,j,k] == (c[i,j,k]-c[i,k,j]+c[j,k,i]-c[j,i,k]+c[k,i,j]-c[k,j,i])/6 ....: for i in range(3) for j in range(3) for k in range(3)) True
>>> from sage.all import * >>> all(s[i,j,k] == (c[i,j,k]-c[i,k,j]+c[j,k,i]-c[j,i,k]+c[k,i,j]-c[k,j,i])/Integer(6) ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True
Antisymmetrization over already antisymmetric indices does not change anything:
sage: s1 = s.antisymmetrize(1,2) ; s1 Fully antisymmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s1 == s True sage: c1 = c.antisymmetrize(1,2) ; c1 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2) sage: c1 == c True
>>> from sage.all import * >>> s1 = s.antisymmetrize(Integer(1),Integer(2)) ; s1 Fully antisymmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s1 == s True >>> c1 = c.antisymmetrize(Integer(1),Integer(2)) ; c1 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2) >>> c1 == c True
But in general, antisymmetrization may alter previous antisymmetries:
sage: c2 = c.antisymmetrize(0,1) ; c2 # the antisymmetry (2,3) is lost: 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) sage: c2 == c False sage: c = s*a ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1, 2) sage: s = c.antisymmetrize(1,3) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 2), with antisymmetry on the index positions (1, 3) sage: s._antisym # the antisymmetry (0,1,2) has been reduced to (0,2), since 1 is involved in the new antisymmetry (1,3): ((0, 2), (1, 3))
>>> from sage.all import * >>> c2 = c.antisymmetrize(Integer(0),Integer(1)) ; c2 # the antisymmetry (2,3) is lost: 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) >>> c2 == c False >>> c = s*a ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1, 2) >>> s = c.antisymmetrize(Integer(1),Integer(3)) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 2), with antisymmetry on the index positions (1, 3) >>> s._antisym # the antisymmetry (0,1,2) has been reduced to (0,2), since 1 is involved in the new antisymmetry (1,3): ((0, 2), (1, 3))
Partial antisymmetrization of 4-indices components with a symmetry on the first two indices:
sage: a = CompFullySym(QQ, V.basis(), 2) sage: a[:] = [[-2,1,3], [1,0,-5], [3,-5,4]] sage: b = Components(QQ, V.basis(), 2) sage: b[:] = [[1,2,3], [5,7,11], [13,17,19]] sage: c = a*b ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) sage: s = c.antisymmetrize(2,3) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3)
>>> from sage.all import * >>> a = CompFullySym(QQ, V.basis(), Integer(2)) >>> a[:] = [[-Integer(2),Integer(1),Integer(3)], [Integer(1),Integer(0),-Integer(5)], [Integer(3),-Integer(5),Integer(4)]] >>> b = Components(QQ, V.basis(), Integer(2)) >>> b[:] = [[Integer(1),Integer(2),Integer(3)], [Integer(5),Integer(7),Integer(11)], [Integer(13),Integer(17),Integer(19)]] >>> c = a*b ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) >>> s = c.antisymmetrize(Integer(2),Integer(3)) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3)
Some check of the antisymmetrization:
sage: all(s[2,2,i,j] == (c[2,2,i,j] - c[2,2,j,i])/2 ....: for i in range(3) for j in range(i,3)) True
>>> from sage.all import * >>> all(s[Integer(2),Integer(2),i,j] == (c[Integer(2),Integer(2),i,j] - c[Integer(2),Integer(2),j,i])/Integer(2) ... for i in range(Integer(3)) for j in range(i,Integer(3))) True
The full antisymmetrization results in zero because of the symmetry on the first two indices:
sage: s = c.antisymmetrize() ; s Fully antisymmetric 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s == 0 True
>>> from sage.all import * >>> s = c.antisymmetrize() ; s Fully antisymmetric 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s == Integer(0) True
Similarly, the partial antisymmetrization on the first two indices results in zero:
sage: s = c.antisymmetrize(0,1) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) sage: s == 0 True
>>> from sage.all import * >>> s = c.antisymmetrize(Integer(0),Integer(1)) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) >>> s == Integer(0) True
The partial antisymmetrization on the positions \((0, 2)\) destroys the symmetry on \((0, 1)\):
sage: s = c.antisymmetrize(0,2) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 2) sage: s != 0 True sage: s[0,1,2,1] 27/2 sage: s[1,0,2,1] # the symmetry (0,1) is lost -2 sage: s[2,1,0,1] # the antisymmetry (0,2) holds -27/2
>>> from sage.all import * >>> s = c.antisymmetrize(Integer(0),Integer(2)) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 2) >>> s != Integer(0) True >>> s[Integer(0),Integer(1),Integer(2),Integer(1)] 27/2 >>> s[Integer(1),Integer(0),Integer(2),Integer(1)] # the symmetry (0,1) is lost -2 >>> s[Integer(2),Integer(1),Integer(0),Integer(1)] # the antisymmetry (0,2) holds -27/2
- non_redundant_index_generator()[source]¶
Generator of indices, with only ordered indices in case of symmetries, so that only non-redundant indices are generated.
OUTPUT: an iterable index
EXAMPLES:
Indices on a 2-dimensional space:
sage: from sage.tensor.modules.comp import Components, CompWithSym, \ ....: CompFullySym, CompFullyAntiSym sage: V = VectorSpace(QQ, 2) sage: c = CompFullySym(QQ, V.basis(), 2) sage: list(c.non_redundant_index_generator()) [(0, 0), (0, 1), (1, 1)] sage: c = CompFullySym(QQ, V.basis(), 2, start_index=1) sage: list(c.non_redundant_index_generator()) [(1, 1), (1, 2), (2, 2)] sage: c = CompFullyAntiSym(QQ, V.basis(), 2) sage: list(c.non_redundant_index_generator()) [(0, 1)]
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components, CompWithSym, CompFullySym, CompFullyAntiSym >>> V = VectorSpace(QQ, Integer(2)) >>> c = CompFullySym(QQ, V.basis(), Integer(2)) >>> list(c.non_redundant_index_generator()) [(0, 0), (0, 1), (1, 1)] >>> c = CompFullySym(QQ, V.basis(), Integer(2), start_index=Integer(1)) >>> list(c.non_redundant_index_generator()) [(1, 1), (1, 2), (2, 2)] >>> c = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> list(c.non_redundant_index_generator()) [(0, 1)]
Indices on a 3-dimensional space:
sage: V = VectorSpace(QQ, 3) sage: c = CompFullySym(QQ, V.basis(), 2) sage: list(c.non_redundant_index_generator()) [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)] sage: c = CompFullySym(QQ, V.basis(), 2, start_index=1) sage: list(c.non_redundant_index_generator()) [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] sage: c = CompFullyAntiSym(QQ, V.basis(), 2) sage: list(c.non_redundant_index_generator()) [(0, 1), (0, 2), (1, 2)] sage: c = CompWithSym(QQ, V.basis(), 3, sym=(1,2)) # symmetry on the last two indices sage: list(c.non_redundant_index_generator()) [(0, 0, 0), (1, 0, 0), (2, 0, 0), (0, 0, 1), (1, 0, 1), (2, 0, 1), (0, 0, 2), (1, 0, 2), (2, 0, 2), (0, 1, 1), (1, 1, 1), (2, 1, 1), (0, 1, 2), (1, 1, 2), (2, 1, 2), (0, 2, 2), (1, 2, 2), (2, 2, 2)] sage: c = CompWithSym(QQ, V.basis(), 3, antisym=(1,2)) # antisymmetry on the last two indices sage: list(c.non_redundant_index_generator()) [(0, 0, 1), (1, 0, 1), (2, 0, 1), (0, 0, 2), (1, 0, 2), (2, 0, 2), (0, 1, 2), (1, 1, 2), (2, 1, 2)] sage: c = CompFullySym(QQ, V.basis(), 3) sage: list(c.non_redundant_index_generator()) [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)] sage: c = CompFullyAntiSym(QQ, V.basis(), 3) sage: list(c.non_redundant_index_generator()) [(0, 1, 2)]
>>> from sage.all import * >>> V = VectorSpace(QQ, Integer(3)) >>> c = CompFullySym(QQ, V.basis(), Integer(2)) >>> list(c.non_redundant_index_generator()) [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)] >>> c = CompFullySym(QQ, V.basis(), Integer(2), start_index=Integer(1)) >>> list(c.non_redundant_index_generator()) [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] >>> c = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> list(c.non_redundant_index_generator()) [(0, 1), (0, 2), (1, 2)] >>> c = CompWithSym(QQ, V.basis(), Integer(3), sym=(Integer(1),Integer(2))) # symmetry on the last two indices >>> list(c.non_redundant_index_generator()) [(0, 0, 0), (1, 0, 0), (2, 0, 0), (0, 0, 1), (1, 0, 1), (2, 0, 1), (0, 0, 2), (1, 0, 2), (2, 0, 2), (0, 1, 1), (1, 1, 1), (2, 1, 1), (0, 1, 2), (1, 1, 2), (2, 1, 2), (0, 2, 2), (1, 2, 2), (2, 2, 2)] >>> c = CompWithSym(QQ, V.basis(), Integer(3), antisym=(Integer(1),Integer(2))) # antisymmetry on the last two indices >>> list(c.non_redundant_index_generator()) [(0, 0, 1), (1, 0, 1), (2, 0, 1), (0, 0, 2), (1, 0, 2), (2, 0, 2), (0, 1, 2), (1, 1, 2), (2, 1, 2)] >>> c = CompFullySym(QQ, V.basis(), Integer(3)) >>> list(c.non_redundant_index_generator()) [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)] >>> c = CompFullyAntiSym(QQ, V.basis(), Integer(3)) >>> list(c.non_redundant_index_generator()) [(0, 1, 2)]
Indices on a 4-dimensional space:
sage: V = VectorSpace(QQ, 4) sage: c = Components(QQ, V.basis(), 1) sage: list(c.non_redundant_index_generator()) [(0,), (1,), (2,), (3,)] sage: c = CompFullyAntiSym(QQ, V.basis(), 2) sage: list(c.non_redundant_index_generator()) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] sage: c = CompFullyAntiSym(QQ, V.basis(), 3) sage: list(c.non_redundant_index_generator()) [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)] sage: c = CompFullyAntiSym(QQ, V.basis(), 4) sage: list(c.non_redundant_index_generator()) [(0, 1, 2, 3)] sage: c = CompFullyAntiSym(QQ, V.basis(), 5) sage: list(c.non_redundant_index_generator()) # nothing since c is identically zero in this case (for 5 > 4) []
>>> from sage.all import * >>> V = VectorSpace(QQ, Integer(4)) >>> c = Components(QQ, V.basis(), Integer(1)) >>> list(c.non_redundant_index_generator()) [(0,), (1,), (2,), (3,)] >>> c = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> list(c.non_redundant_index_generator()) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] >>> c = CompFullyAntiSym(QQ, V.basis(), Integer(3)) >>> list(c.non_redundant_index_generator()) [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)] >>> c = CompFullyAntiSym(QQ, V.basis(), Integer(4)) >>> list(c.non_redundant_index_generator()) [(0, 1, 2, 3)] >>> c = CompFullyAntiSym(QQ, V.basis(), Integer(5)) >>> list(c.non_redundant_index_generator()) # nothing since c is identically zero in this case (for 5 > 4) []
- swap_adjacent_indices(pos1, pos2, pos3)[source]¶
Swap two adjacent sets of indices.
This method is essentially required to reorder the covariant and contravariant indices in the computation of a tensor product.
The symmetries are preserved and the corresponding indices are adjusted consequently.
INPUT:
pos1
– position of the first index of set 1 (with the convention position=0 for the first slot)pos2
– position of the first index of set 2 = 1 + position of the last index of set 1 (since the two sets are adjacent)pos3
– 1 + position of the last index of set 2
OUTPUT: components with index set 1 permuted with index set 2
EXAMPLES:
Swap of the index in position 0 with the pair of indices in position (1,2) in a set of components antisymmetric with respect to the indices in position (1,2):
sage: from sage.tensor.modules.comp import CompWithSym sage: V = VectorSpace(QQ, 3) sage: c = CompWithSym(QQ, V.basis(), 3, antisym=(1,2)) sage: c[0,0,1], c[0,0,2], c[0,1,2] = (1,2,3) sage: c[1,0,1], c[1,0,2], c[1,1,2] = (4,5,6) sage: c[2,0,1], c[2,0,2], c[2,1,2] = (7,8,9) sage: c[:] [[[0, 1, 2], [-1, 0, 3], [-2, -3, 0]], [[0, 4, 5], [-4, 0, 6], [-5, -6, 0]], [[0, 7, 8], [-7, 0, 9], [-8, -9, 0]]] sage: c1 = c.swap_adjacent_indices(0,1,3) sage: c._antisym # c is antisymmetric with respect to the last pair of indices... ((1, 2),) sage: c1._antisym #...while c1 is antisymmetric with respect to the first pair of indices ((0, 1),) sage: c[0,1,2] 3 sage: c1[1,2,0] 3 sage: c1[2,1,0] -3
>>> from sage.all import * >>> from sage.tensor.modules.comp import CompWithSym >>> V = VectorSpace(QQ, Integer(3)) >>> c = CompWithSym(QQ, V.basis(), Integer(3), antisym=(Integer(1),Integer(2))) >>> c[Integer(0),Integer(0),Integer(1)], c[Integer(0),Integer(0),Integer(2)], c[Integer(0),Integer(1),Integer(2)] = (Integer(1),Integer(2),Integer(3)) >>> c[Integer(1),Integer(0),Integer(1)], c[Integer(1),Integer(0),Integer(2)], c[Integer(1),Integer(1),Integer(2)] = (Integer(4),Integer(5),Integer(6)) >>> c[Integer(2),Integer(0),Integer(1)], c[Integer(2),Integer(0),Integer(2)], c[Integer(2),Integer(1),Integer(2)] = (Integer(7),Integer(8),Integer(9)) >>> c[:] [[[0, 1, 2], [-1, 0, 3], [-2, -3, 0]], [[0, 4, 5], [-4, 0, 6], [-5, -6, 0]], [[0, 7, 8], [-7, 0, 9], [-8, -9, 0]]] >>> c1 = c.swap_adjacent_indices(Integer(0),Integer(1),Integer(3)) >>> c._antisym # c is antisymmetric with respect to the last pair of indices... ((1, 2),) >>> c1._antisym #...while c1 is antisymmetric with respect to the first pair of indices ((0, 1),) >>> c[Integer(0),Integer(1),Integer(2)] 3 >>> c1[Integer(1),Integer(2),Integer(0)] 3 >>> c1[Integer(2),Integer(1),Integer(0)] -3
- symmetrize(*pos)[source]¶
Symmetrization over the given index positions.
INPUT:
pos
– list of index positions involved in the symmetrization (with the conventionposition=0
for the first slot); if none, the symmetrization is performed over all the indices
OUTPUT:
an instance of
CompWithSym
describing the symmetrized components
EXAMPLES:
Symmetrization of 3-indices components on a 3-dimensional space:
sage: from sage.tensor.modules.comp import Components, CompWithSym, \ ....: CompFullySym, CompFullyAntiSym sage: V = VectorSpace(QQ, 3) sage: c = Components(QQ, V.basis(), 3) sage: c[:] = [[[1,2,3], [4,5,6], [7,8,9]], [[10,11,12], [13,14,15], [16,17,18]], [[19,20,21], [22,23,24], [25,26,27]]] sage: cs = c.symmetrize(0,1) ; cs 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) sage: s = cs.symmetrize() ; s Fully symmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: cs[:], s[:] ([[[1, 2, 3], [7, 8, 9], [13, 14, 15]], [[7, 8, 9], [13, 14, 15], [19, 20, 21]], [[13, 14, 15], [19, 20, 21], [25, 26, 27]]], [[[1, 16/3, 29/3], [16/3, 29/3, 14], [29/3, 14, 55/3]], [[16/3, 29/3, 14], [29/3, 14, 55/3], [14, 55/3, 68/3]], [[29/3, 14, 55/3], [14, 55/3, 68/3], [55/3, 68/3, 27]]]) sage: s == c.symmetrize() # should be true True sage: s1 = cs.symmetrize(0,1) ; s1 # should return a copy of cs 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) sage: s1 == cs # check that s1 is a copy of cs True
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components, CompWithSym, CompFullySym, CompFullyAntiSym >>> V = VectorSpace(QQ, Integer(3)) >>> c = Components(QQ, V.basis(), Integer(3)) >>> c[:] = [[[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], [[Integer(10),Integer(11),Integer(12)], [Integer(13),Integer(14),Integer(15)], [Integer(16),Integer(17),Integer(18)]], [[Integer(19),Integer(20),Integer(21)], [Integer(22),Integer(23),Integer(24)], [Integer(25),Integer(26),Integer(27)]]] >>> cs = c.symmetrize(Integer(0),Integer(1)) ; cs 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) >>> s = cs.symmetrize() ; s Fully symmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> cs[:], s[:] ([[[1, 2, 3], [7, 8, 9], [13, 14, 15]], [[7, 8, 9], [13, 14, 15], [19, 20, 21]], [[13, 14, 15], [19, 20, 21], [25, 26, 27]]], [[[1, 16/3, 29/3], [16/3, 29/3, 14], [29/3, 14, 55/3]], [[16/3, 29/3, 14], [29/3, 14, 55/3], [14, 55/3, 68/3]], [[29/3, 14, 55/3], [14, 55/3, 68/3], [55/3, 68/3, 27]]]) >>> s == c.symmetrize() # should be true True >>> s1 = cs.symmetrize(Integer(0),Integer(1)) ; s1 # should return a copy of cs 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) >>> s1 == cs # check that s1 is a copy of cs True
Let us now start with a symmetry on the last two indices:
sage: cs1 = c.symmetrize(1,2) ; cs1 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2) sage: s2 = cs1.symmetrize() ; s2 Fully symmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s2 == c.symmetrize() True
>>> from sage.all import * >>> cs1 = c.symmetrize(Integer(1),Integer(2)) ; cs1 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2) >>> s2 = cs1.symmetrize() ; s2 Fully symmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s2 == c.symmetrize() True
Symmetrization alters pre-existing symmetries: let us symmetrize w.r.t. the index positions \((1, 2)\) a set of components that is symmetric w.r.t. the index positions \((0, 1)\):
sage: cs = c.symmetrize(0,1) ; cs 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) sage: css = cs.symmetrize(1,2) sage: css # the symmetry (0,1) has been lost: 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2) sage: css[:] [[[1, 9/2, 8], [9/2, 8, 23/2], [8, 23/2, 15]], [[7, 21/2, 14], [21/2, 14, 35/2], [14, 35/2, 21]], [[13, 33/2, 20], [33/2, 20, 47/2], [20, 47/2, 27]]] sage: cs[:] [[[1, 2, 3], [7, 8, 9], [13, 14, 15]], [[7, 8, 9], [13, 14, 15], [19, 20, 21]], [[13, 14, 15], [19, 20, 21], [25, 26, 27]]] sage: css == c.symmetrize() # css differs from the full symmetrized version False sage: css.symmetrize() == c.symmetrize() # one has to symmetrize css over all indices to recover it True
>>> from sage.all import * >>> cs = c.symmetrize(Integer(0),Integer(1)) ; cs 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) >>> css = cs.symmetrize(Integer(1),Integer(2)) >>> css # the symmetry (0,1) has been lost: 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2) >>> css[:] [[[1, 9/2, 8], [9/2, 8, 23/2], [8, 23/2, 15]], [[7, 21/2, 14], [21/2, 14, 35/2], [14, 35/2, 21]], [[13, 33/2, 20], [33/2, 20, 47/2], [20, 47/2, 27]]] >>> cs[:] [[[1, 2, 3], [7, 8, 9], [13, 14, 15]], [[7, 8, 9], [13, 14, 15], [19, 20, 21]], [[13, 14, 15], [19, 20, 21], [25, 26, 27]]] >>> css == c.symmetrize() # css differs from the full symmetrized version False >>> css.symmetrize() == c.symmetrize() # one has to symmetrize css over all indices to recover it True
Another example of symmetry alteration: symmetrization over \((0, 1)\) of a 4-indices set of components that is symmetric w.r.t. \((1, 2, 3)\):
sage: v = Components(QQ, V.basis(), 1) sage: v[:] = (-2,1,4) sage: a = v*s ; a 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2, 3) sage: a1 = a.symmetrize(0,1) ; a1 # the symmetry (1,2,3) has been reduced to (2,3): 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) sage: a1._sym # a1 has two distinct symmetries: ((0, 1), (2, 3)) sage: a[0,1,2,0] == a[0,0,2,1] # a is symmetric w.r.t. positions 1 and 3 True sage: a1[0,1,2,0] == a1[0,0,2,1] # a1 is not False sage: a1[0,1,2,0] == a1[1,0,2,0] # but it is symmetric w.r.t. position 0 and 1 True sage: a[0,1,2,0] == a[1,0,2,0] # while a is not False
>>> from sage.all import * >>> v = Components(QQ, V.basis(), Integer(1)) >>> v[:] = (-Integer(2),Integer(1),Integer(4)) >>> a = v*s ; a 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2, 3) >>> a1 = a.symmetrize(Integer(0),Integer(1)) ; a1 # the symmetry (1,2,3) has been reduced to (2,3): 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) >>> a1._sym # a1 has two distinct symmetries: ((0, 1), (2, 3)) >>> a[Integer(0),Integer(1),Integer(2),Integer(0)] == a[Integer(0),Integer(0),Integer(2),Integer(1)] # a is symmetric w.r.t. positions 1 and 3 True >>> a1[Integer(0),Integer(1),Integer(2),Integer(0)] == a1[Integer(0),Integer(0),Integer(2),Integer(1)] # a1 is not False >>> a1[Integer(0),Integer(1),Integer(2),Integer(0)] == a1[Integer(1),Integer(0),Integer(2),Integer(0)] # but it is symmetric w.r.t. position 0 and 1 True >>> a[Integer(0),Integer(1),Integer(2),Integer(0)] == a[Integer(1),Integer(0),Integer(2),Integer(0)] # while a is not False
Partial symmetrization of 4-indices components with an antisymmetry on the last two indices:
sage: a = Components(QQ, V.basis(), 2) sage: a[:] = [[-1,2,3], [4,5,-6], [7,8,9]] sage: b = CompFullyAntiSym(QQ, V.basis(), 2) sage: b[0,1], b[0,2], b[1,2] = (2, 4, 8) sage: c = a*b ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (2, 3) sage: s = c.symmetrize(0,1) ; s # symmetrization on the first two indices 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3) sage: s[0,1,2,1] == (c[0,1,2,1] + c[1,0,2,1]) / 2 # check of the symmetrization True sage: s = c.symmetrize() ; s # symmetrization over all the indices Fully symmetric 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s == 0 # the full symmetrization results in zero due to the antisymmetry on the last two indices True sage: s = c.symmetrize(2,3) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (2, 3) sage: s == 0 # must be zero since the symmetrization has been performed on the antisymmetric indices True sage: s = c.symmetrize(0,2) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 2) sage: s != 0 # s is not zero, but the antisymmetry on (2,3) is lost because the position 2 is involved in the new symmetry True
>>> from sage.all import * >>> a = Components(QQ, V.basis(), Integer(2)) >>> a[:] = [[-Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),-Integer(6)], [Integer(7),Integer(8),Integer(9)]] >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> b[Integer(0),Integer(1)], b[Integer(0),Integer(2)], b[Integer(1),Integer(2)] = (Integer(2), Integer(4), Integer(8)) >>> c = a*b ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (2, 3) >>> s = c.symmetrize(Integer(0),Integer(1)) ; s # symmetrization on the first two indices 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3) >>> s[Integer(0),Integer(1),Integer(2),Integer(1)] == (c[Integer(0),Integer(1),Integer(2),Integer(1)] + c[Integer(1),Integer(0),Integer(2),Integer(1)]) / Integer(2) # check of the symmetrization True >>> s = c.symmetrize() ; s # symmetrization over all the indices Fully symmetric 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s == Integer(0) # the full symmetrization results in zero due to the antisymmetry on the last two indices True >>> s = c.symmetrize(Integer(2),Integer(3)) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (2, 3) >>> s == Integer(0) # must be zero since the symmetrization has been performed on the antisymmetric indices True >>> s = c.symmetrize(Integer(0),Integer(2)) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 2) >>> s != Integer(0) # s is not zero, but the antisymmetry on (2,3) is lost because the position 2 is involved in the new symmetry True
Partial symmetrization of 4-indices components with an antisymmetry on the last three indices:
sage: a = Components(QQ, V.basis(), 1) sage: a[:] = (1, -2, 3) sage: b = CompFullyAntiSym(QQ, V.basis(), 3) sage: b[0,1,2] = 4 sage: c = a*b ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2, 3) sage: s = c.symmetrize(0,1) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3)
>>> from sage.all import * >>> a = Components(QQ, V.basis(), Integer(1)) >>> a[:] = (Integer(1), -Integer(2), Integer(3)) >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(3)) >>> b[Integer(0),Integer(1),Integer(2)] = Integer(4) >>> c = a*b ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2, 3) >>> s = c.symmetrize(Integer(0),Integer(1)) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3)
Note that the antisymmetry on \((1, 2, 3)\) has been reduced to \((2, 3)\) only:
sage: s = c.symmetrize(1,2) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2) sage: s == 0 # because (1,2) are involved in the original antisymmetry True
>>> from sage.all import * >>> s = c.symmetrize(Integer(1),Integer(2)) ; s 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2) >>> s == Integer(0) # because (1,2) are involved in the original antisymmetry True
- trace(pos1, pos2)[source]¶
Index contraction, taking care of the symmetries.
INPUT:
pos1
– position of the first index for the contraction (with the convention position=0 for the first slot)pos2
– position of the second index for the contraction
OUTPUT:
set of components resulting from the (pos1, pos2) contraction
EXAMPLES:
Self-contraction of symmetric 2-indices components:
sage: from sage.tensor.modules.comp import Components, CompWithSym, \ ....: CompFullySym, CompFullyAntiSym sage: V = VectorSpace(QQ, 3) sage: a = CompFullySym(QQ, V.basis(), 2) sage: a[:] = [[1,2,3],[2,4,5],[3,5,6]] sage: a.trace(0,1) 11 sage: a[0,0] + a[1,1] + a[2,2] 11
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components, CompWithSym, CompFullySym, CompFullyAntiSym >>> V = VectorSpace(QQ, Integer(3)) >>> a = CompFullySym(QQ, V.basis(), Integer(2)) >>> a[:] = [[Integer(1),Integer(2),Integer(3)],[Integer(2),Integer(4),Integer(5)],[Integer(3),Integer(5),Integer(6)]] >>> a.trace(Integer(0),Integer(1)) 11 >>> a[Integer(0),Integer(0)] + a[Integer(1),Integer(1)] + a[Integer(2),Integer(2)] 11
Self-contraction of antisymmetric 2-indices components:
sage: b = CompFullyAntiSym(QQ, V.basis(), 2) sage: b[0,1], b[0,2], b[1,2] = (3, -2, 1) sage: b.trace(0,1) # must be zero by antisymmetry 0
>>> from sage.all import * >>> b = CompFullyAntiSym(QQ, V.basis(), Integer(2)) >>> b[Integer(0),Integer(1)], b[Integer(0),Integer(2)], b[Integer(1),Integer(2)] = (Integer(3), -Integer(2), Integer(1)) >>> b.trace(Integer(0),Integer(1)) # must be zero by antisymmetry 0
Self-contraction of 3-indices components with one symmetry:
sage: v = Components(QQ, V.basis(), 1) sage: v[:] = (-2, 4, -8) sage: c = v*b ; c 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2) sage: s = c.trace(0,1) ; s 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s[:] [-28, 2, 8] sage: [sum(v[k]*b[k,i] for k in range(3)) for i in range(3)] # check [-28, 2, 8] sage: s = c.trace(1,2) ; s 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s[:] # is zero by antisymmetry [0, 0, 0] sage: c = b*v ; c 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) sage: s = c.trace(0,1) sage: s[:] # is zero by antisymmetry [0, 0, 0] sage: s = c.trace(1,2) ; s[:] [28, -2, -8] sage: [sum(b[i,k]*v[k] for k in range(3)) for i in range(3)] # check [28, -2, -8]
>>> from sage.all import * >>> v = Components(QQ, V.basis(), Integer(1)) >>> v[:] = (-Integer(2), Integer(4), -Integer(8)) >>> c = v*b ; c 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2) >>> s = c.trace(Integer(0),Integer(1)) ; s 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s[:] [-28, 2, 8] >>> [sum(v[k]*b[k,i] for k in range(Integer(3))) for i in range(Integer(3))] # check [-28, 2, 8] >>> s = c.trace(Integer(1),Integer(2)) ; s 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s[:] # is zero by antisymmetry [0, 0, 0] >>> c = b*v ; c 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) >>> s = c.trace(Integer(0),Integer(1)) >>> s[:] # is zero by antisymmetry [0, 0, 0] >>> s = c.trace(Integer(1),Integer(2)) ; s[:] [28, -2, -8] >>> [sum(b[i,k]*v[k] for k in range(Integer(3))) for i in range(Integer(3))] # check [28, -2, -8]
Self-contraction of 4-indices components with two symmetries:
sage: c = a*b ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3) sage: s = c.trace(0,1) ; s # the symmetry on (0,1) is lost: Fully antisymmetric 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s[:] [ 0 33 -22] [-33 0 11] [ 22 -11 0] sage: [[sum(c[k,k,i,j] for k in range(3)) for j in range(3)] for i in range(3)] # check [[0, 33, -22], [-33, 0, 11], [22, -11, 0]] sage: s = c.trace(1,2) ; s # both symmetries are lost by this contraction 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s[:] [ 0 0 0] [-2 1 0] [-3 3 -1] sage: [[sum(c[i,k,k,j] for k in range(3)) for j in range(3)] for i in range(3)] # check [[0, 0, 0], [-2, 1, 0], [-3, 3, -1]]
>>> from sage.all import * >>> c = a*b ; c 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3) >>> s = c.trace(Integer(0),Integer(1)) ; s # the symmetry on (0,1) is lost: Fully antisymmetric 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s[:] [ 0 33 -22] [-33 0 11] [ 22 -11 0] >>> [[sum(c[k,k,i,j] for k in range(Integer(3))) for j in range(Integer(3))] for i in range(Integer(3))] # check [[0, 33, -22], [-33, 0, 11], [22, -11, 0]] >>> s = c.trace(Integer(1),Integer(2)) ; s # both symmetries are lost by this contraction 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s[:] [ 0 0 0] [-2 1 0] [-3 3 -1] >>> [[sum(c[i,k,k,j] for k in range(Integer(3))) for j in range(Integer(3))] for i in range(Integer(3))] # check [[0, 0, 0], [-2, 1, 0], [-3, 3, -1]]
- class sage.tensor.modules.comp.Components(ring, frame, nb_indices, start_index=0, output_formatter=None)[source]¶
Bases:
SageObject
Indexed set of ring elements forming some components with respect to a given “frame”.
The “frame” can be a basis of some vector space or a vector frame on some manifold (i.e. a field of bases). The stored quantities can be tensor components or non-tensorial quantities, such as connection coefficients or structure coefficients. The symmetries over some indices are dealt by subclasses of the class
Components
.INPUT:
ring
– commutative ring in which each component takes its valueframe
– frame with respect to which the components are defined; whatever typeframe
is, it should have a method__len__()
implemented, so thatlen(frame)
returns the dimension, i.e. the size of a single index rangenb_indices
– number of integer indices labeling the componentsstart_index
– (default: 0) first value of a single index; accordingly a component index i must obeystart_index <= i <= start_index + dim - 1
, wheredim = len(frame)
.output_formatter
– (default:None
) function or unbound method called to format the output of the component access operator[...]
(method __getitem__);output_formatter
must take 1 or 2 arguments: the 1st argument must be an element ofring
and the second one, if any, some format specification.
EXAMPLES:
Set of components with 2 indices on a 3-dimensional vector space, the frame being some basis of the vector space:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) sage: basis = V.basis() ; basis [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: c = Components(QQ, basis, 2) ; c 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ]
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ,Integer(3)) >>> basis = V.basis() ; basis [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> c = Components(QQ, basis, Integer(2)) ; c 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ]
Actually, the frame can be any object that has some length, i.e. on which the function
len()
can be called:sage: basis1 = V.gens() ; basis1 ((1, 0, 0), (0, 1, 0), (0, 0, 1)) sage: c1 = Components(QQ, basis1, 2) ; c1 2-indices components w.r.t. ((1, 0, 0), (0, 1, 0), (0, 0, 1)) sage: basis2 = ['a', 'b' , 'c'] sage: c2 = Components(QQ, basis2, 2) ; c2 2-indices components w.r.t. ['a', 'b', 'c']
>>> from sage.all import * >>> basis1 = V.gens() ; basis1 ((1, 0, 0), (0, 1, 0), (0, 0, 1)) >>> c1 = Components(QQ, basis1, Integer(2)) ; c1 2-indices components w.r.t. ((1, 0, 0), (0, 1, 0), (0, 0, 1)) >>> basis2 = ['a', 'b' , 'c'] >>> c2 = Components(QQ, basis2, Integer(2)) ; c2 2-indices components w.r.t. ['a', 'b', 'c']
By default, the indices range from \(0\) to \(n-1\), where \(n\) is the length of the frame. This can be changed via the argument
start_index
:sage: c1 = Components(QQ, basis, 2, start_index=1) sage: c1[0,1] Traceback (most recent call last): ... IndexError: index out of range: 0 not in [1, 3] sage: c[0,1] # for c, the index 0 is OK 0 sage: c[0,1] = -3 sage: c1[:] = c[:] # list copy of all components sage: c1[1,2] # (1,2) = (0,1) shifted by 1 -3
>>> from sage.all import * >>> c1 = Components(QQ, basis, Integer(2), start_index=Integer(1)) >>> c1[Integer(0),Integer(1)] Traceback (most recent call last): ... IndexError: index out of range: 0 not in [1, 3] >>> c[Integer(0),Integer(1)] # for c, the index 0 is OK 0 >>> c[Integer(0),Integer(1)] = -Integer(3) >>> c1[:] = c[:] # list copy of all components >>> c1[Integer(1),Integer(2)] # (1,2) = (0,1) shifted by 1 -3
If some formatter function or unbound method is provided via the argument
output_formatter
, it is used to change the output of the access operator[...]
:sage: a = Components(QQ, basis, 2, output_formatter=Rational.numerical_approx) sage: a[1,2] = 1/3 sage: a[1,2] 0.333333333333333
>>> from sage.all import * >>> a = Components(QQ, basis, Integer(2), output_formatter=Rational.numerical_approx) >>> a[Integer(1),Integer(2)] = Integer(1)/Integer(3) >>> a[Integer(1),Integer(2)] 0.333333333333333
The format can be passed to the formatter as the last argument of the access operator
[...]
:sage: a[1,2,10] # here the format is 10, for 10 bits of precision 0.33 sage: a[1,2,100] 0.33333333333333333333333333333
>>> from sage.all import * >>> a[Integer(1),Integer(2),Integer(10)] # here the format is 10, for 10 bits of precision 0.33 >>> a[Integer(1),Integer(2),Integer(100)] 0.33333333333333333333333333333
The raw (unformatted) components are then accessed by the double bracket operator:
sage: a[[1,2]] 1/3
>>> from sage.all import * >>> a[[Integer(1),Integer(2)]] 1/3
For sets of components declared without any output formatter, there is no difference between
[...]
and[[...]]
:sage: c[1,2] = 1/3 sage: c[1,2], c[[1,2]] (1/3, 1/3)
>>> from sage.all import * >>> c[Integer(1),Integer(2)] = Integer(1)/Integer(3) >>> c[Integer(1),Integer(2)], c[[Integer(1),Integer(2)]] (1/3, 1/3)
The formatter is also used for the complete list of components:
sage: a[:] [0.000000000000000 0.000000000000000 0.000000000000000] [0.000000000000000 0.000000000000000 0.333333333333333] [0.000000000000000 0.000000000000000 0.000000000000000] sage: a[:,10] # with a format different from the default one (53 bits) [0.00 0.00 0.00] [0.00 0.00 0.33] [0.00 0.00 0.00]
>>> from sage.all import * >>> a[:] [0.000000000000000 0.000000000000000 0.000000000000000] [0.000000000000000 0.000000000000000 0.333333333333333] [0.000000000000000 0.000000000000000 0.000000000000000] >>> a[:,Integer(10)] # with a format different from the default one (53 bits) [0.00 0.00 0.00] [0.00 0.00 0.33] [0.00 0.00 0.00]
The complete list of components in raw form can be recovered by the double bracket operator, replacing
:
byslice(None)
(sincea[[:]]
generates a Python syntax error):sage: a[[slice(None)]] [ 0 0 0] [ 0 0 1/3] [ 0 0 0]
>>> from sage.all import * >>> a[[slice(None)]] [ 0 0 0] [ 0 0 1/3] [ 0 0 0]
Another example of formatter: the Python built-in function
str()
to generate string outputs:sage: b = Components(QQ, V.basis(), 1, output_formatter=str) sage: b[:] = (1, 0, -4) sage: b[:] ['1', '0', '-4']
>>> from sage.all import * >>> b = Components(QQ, V.basis(), Integer(1), output_formatter=str) >>> b[:] = (Integer(1), Integer(0), -Integer(4)) >>> b[:] ['1', '0', '-4']
For such a formatter, 2-indices components are no longer displayed as a matrix:
sage: b = Components(QQ, basis, 2, output_formatter=str) sage: b[0,1] = 1/3 sage: b[:] [['0', '1/3', '0'], ['0', '0', '0'], ['0', '0', '0']]
>>> from sage.all import * >>> b = Components(QQ, basis, Integer(2), output_formatter=str) >>> b[Integer(0),Integer(1)] = Integer(1)/Integer(3) >>> b[:] [['0', '1/3', '0'], ['0', '0', '0'], ['0', '0', '0']]
But unformatted outputs still are:
sage: b[[slice(None)]] [ 0 1/3 0] [ 0 0 0] [ 0 0 0]
>>> from sage.all import * >>> b[[slice(None)]] [ 0 1/3 0] [ 0 0 0] [ 0 0 0]
Internally, the components are stored as a dictionary (
_comp
) whose keys are the indices; only the nonzero components are stored:sage: a[:] [0.000000000000000 0.000000000000000 0.000000000000000] [0.000000000000000 0.000000000000000 0.333333333333333] [0.000000000000000 0.000000000000000 0.000000000000000] sage: a._comp {(1, 2): 1/3} sage: v = Components(QQ, basis, 1) sage: v[:] = (-1, 0, 3) sage: v._comp # random output order of the component dictionary {(0,): -1, (2,): 3}
>>> from sage.all import * >>> a[:] [0.000000000000000 0.000000000000000 0.000000000000000] [0.000000000000000 0.000000000000000 0.333333333333333] [0.000000000000000 0.000000000000000 0.000000000000000] >>> a._comp {(1, 2): 1/3} >>> v = Components(QQ, basis, Integer(1)) >>> v[:] = (-Integer(1), Integer(0), Integer(3)) >>> v._comp # random output order of the component dictionary {(0,): -1, (2,): 3}
ARITHMETIC EXAMPLES:
Unary plus operator:
sage: a = Components(QQ, basis, 1) sage: a[:] = (-1, 0, 3) sage: s = +a ; s[:] [-1, 0, 3] sage: +a == a True
>>> from sage.all import * >>> a = Components(QQ, basis, Integer(1)) >>> a[:] = (-Integer(1), Integer(0), Integer(3)) >>> s = +a ; s[:] [-1, 0, 3] >>> +a == a True
Unary minus operator:
sage: s = -a ; s[:] [1, 0, -3]
>>> from sage.all import * >>> s = -a ; s[:] [1, 0, -3]
Addition:
sage: b = Components(QQ, basis, 1) sage: b[:] = (2, 1, 4) sage: s = a + b ; s[:] [1, 1, 7] sage: a + b == b + a True sage: a + (-a) == 0 True
>>> from sage.all import * >>> b = Components(QQ, basis, Integer(1)) >>> b[:] = (Integer(2), Integer(1), Integer(4)) >>> s = a + b ; s[:] [1, 1, 7] >>> a + b == b + a True >>> a + (-a) == Integer(0) True
Subtraction:
sage: s = a - b ; s[:] [-3, -1, -1] sage: s + b == a True sage: a - b == - (b - a) True
>>> from sage.all import * >>> s = a - b ; s[:] [-3, -1, -1] >>> s + b == a True >>> a - b == - (b - a) True
Multiplication by a scalar:
sage: s = 2*a ; s[:] [-2, 0, 6]
>>> from sage.all import * >>> s = Integer(2)*a ; s[:] [-2, 0, 6]
Division by a scalar:
sage: s = a/2 ; s[:] [-1/2, 0, 3/2] sage: 2*(a/2) == a True
>>> from sage.all import * >>> s = a/Integer(2) ; s[:] [-1/2, 0, 3/2] >>> Integer(2)*(a/Integer(2)) == a True
Tensor product (by means of the operator
*
):sage: c = a*b ; c 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: a[:], b[:] ([-1, 0, 3], [2, 1, 4]) sage: c[:] [-2 -1 -4] [ 0 0 0] [ 6 3 12] sage: d = c*a ; d 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: d[:] [[[2, 0, -6], [1, 0, -3], [4, 0, -12]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[-6, 0, 18], [-3, 0, 9], [-12, 0, 36]]] sage: d[0,1,2] == a[0]*b[1]*a[2] True
>>> from sage.all import * >>> c = a*b ; c 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> a[:], b[:] ([-1, 0, 3], [2, 1, 4]) >>> c[:] [-2 -1 -4] [ 0 0 0] [ 6 3 12] >>> d = c*a ; d 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> d[:] [[[2, 0, -6], [1, 0, -3], [4, 0, -12]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[-6, 0, 18], [-3, 0, 9], [-12, 0, 36]]] >>> d[Integer(0),Integer(1),Integer(2)] == a[Integer(0)]*b[Integer(1)]*a[Integer(2)] True
- antisymmetrize(*pos)[source]¶
Antisymmetrization over the given index positions.
INPUT:
pos
– list of index positions involved in the antisymmetrization (with the convention position=0 for the first slot); if none, the antisymmetrization is performed over all the indices
OUTPUT: an instance of
CompWithSym
describing the antisymmetrized componentsEXAMPLES:
Antisymmetrization of 2-indices components:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ, 3) sage: c = Components(QQ, V.basis(), 2) sage: c[:] = [[1,2,3], [4,5,6], [7,8,9]] sage: s = c.antisymmetrize() ; s Fully antisymmetric 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: c[:], s[:] ( [1 2 3] [ 0 -1 -2] [4 5 6] [ 1 0 -1] [7 8 9], [ 2 1 0] ) sage: c.antisymmetrize() == c.antisymmetrize(0,1) True
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ, Integer(3)) >>> c = Components(QQ, V.basis(), Integer(2)) >>> c[:] = [[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]] >>> s = c.antisymmetrize() ; s Fully antisymmetric 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> c[:], s[:] ( [1 2 3] [ 0 -1 -2] [4 5 6] [ 1 0 -1] [7 8 9], [ 2 1 0] ) >>> c.antisymmetrize() == c.antisymmetrize(Integer(0),Integer(1)) True
Full antisymmetrization of 3-indices components:
sage: c = Components(QQ, V.basis(), 3) sage: c[:] = [[[-1,-2,3], [4,-5,4], [-7,8,9]], [[10,10,12], [13,-14,15], [-16,17,19]], [[-19,20,21], [1,2,3], [-25,26,27]]] sage: s = c.antisymmetrize() ; s Fully antisymmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: c[:], s[:] ([[[-1, -2, 3], [4, -5, 4], [-7, 8, 9]], [[10, 10, 12], [13, -14, 15], [-16, 17, 19]], [[-19, 20, 21], [1, 2, 3], [-25, 26, 27]]], [[[0, 0, 0], [0, 0, -13/6], [0, 13/6, 0]], [[0, 0, 13/6], [0, 0, 0], [-13/6, 0, 0]], [[0, -13/6, 0], [13/6, 0, 0], [0, 0, 0]]]) sage: all(s[i,j,k] == (c[i,j,k]-c[i,k,j]+c[j,k,i]-c[j,i,k]+c[k,i,j]-c[k,j,i])/6 # Check of the result: ....: for i in range(3) for j in range(3) for k in range(3)) True sage: c.symmetrize() == c.symmetrize(0,1,2) True
>>> from sage.all import * >>> c = Components(QQ, V.basis(), Integer(3)) >>> c[:] = [[[-Integer(1),-Integer(2),Integer(3)], [Integer(4),-Integer(5),Integer(4)], [-Integer(7),Integer(8),Integer(9)]], [[Integer(10),Integer(10),Integer(12)], [Integer(13),-Integer(14),Integer(15)], [-Integer(16),Integer(17),Integer(19)]], [[-Integer(19),Integer(20),Integer(21)], [Integer(1),Integer(2),Integer(3)], [-Integer(25),Integer(26),Integer(27)]]] >>> s = c.antisymmetrize() ; s Fully antisymmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> c[:], s[:] ([[[-1, -2, 3], [4, -5, 4], [-7, 8, 9]], [[10, 10, 12], [13, -14, 15], [-16, 17, 19]], [[-19, 20, 21], [1, 2, 3], [-25, 26, 27]]], [[[0, 0, 0], [0, 0, -13/6], [0, 13/6, 0]], [[0, 0, 13/6], [0, 0, 0], [-13/6, 0, 0]], [[0, -13/6, 0], [13/6, 0, 0], [0, 0, 0]]]) >>> all(s[i,j,k] == (c[i,j,k]-c[i,k,j]+c[j,k,i]-c[j,i,k]+c[k,i,j]-c[k,j,i])/Integer(6) # Check of the result: ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True >>> c.symmetrize() == c.symmetrize(Integer(0),Integer(1),Integer(2)) True
Partial antisymmetrization of 3-indices components:
sage: s = c.antisymmetrize(0,1) ; s # antisymmetrization on the first two indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) sage: c[:], s[:] ([[[-1, -2, 3], [4, -5, 4], [-7, 8, 9]], [[10, 10, 12], [13, -14, 15], [-16, 17, 19]], [[-19, 20, 21], [1, 2, 3], [-25, 26, 27]]], [[[0, 0, 0], [-3, -15/2, -4], [6, -6, -6]], [[3, 15/2, 4], [0, 0, 0], [-17/2, 15/2, 8]], [[-6, 6, 6], [17/2, -15/2, -8], [0, 0, 0]]]) sage: all(s[i,j,k] == (c[i,j,k]-c[j,i,k])/2 # Check of the result: ....: for i in range(3) for j in range(3) for k in range(3)) True sage: s = c.antisymmetrize(1,2) ; s # antisymmetrization on the last two indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2) sage: c[:], s[:] ([[[-1, -2, 3], [4, -5, 4], [-7, 8, 9]], [[10, 10, 12], [13, -14, 15], [-16, 17, 19]], [[-19, 20, 21], [1, 2, 3], [-25, 26, 27]]], [[[0, -3, 5], [3, 0, -2], [-5, 2, 0]], [[0, -3/2, 14], [3/2, 0, -1], [-14, 1, 0]], [[0, 19/2, 23], [-19/2, 0, -23/2], [-23, 23/2, 0]]]) sage: all(s[i,j,k] == (c[i,j,k]-c[i,k,j])/2 # Check of the result: ....: for i in range(3) for j in range(3) for k in range(3)) True sage: s = c.antisymmetrize(0,2) ; s # antisymmetrization on the first and last indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 2) sage: c[:], s[:] ([[[-1, -2, 3], [4, -5, 4], [-7, 8, 9]], [[10, 10, 12], [13, -14, 15], [-16, 17, 19]], [[-19, 20, 21], [1, 2, 3], [-25, 26, 27]]], [[[0, -6, 11], [0, -9, 3/2], [0, 12, 17]], [[6, 0, -4], [9, 0, 13/2], [-12, 0, -7/2]], [[-11, 4, 0], [-3/2, -13/2, 0], [-17, 7/2, 0]]]) sage: all(s[i,j,k] == (c[i,j,k]-c[k,j,i])/2 # Check of the result: ....: for i in range(3) for j in range(3) for k in range(3)) True
>>> from sage.all import * >>> s = c.antisymmetrize(Integer(0),Integer(1)) ; s # antisymmetrization on the first two indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 1) >>> c[:], s[:] ([[[-1, -2, 3], [4, -5, 4], [-7, 8, 9]], [[10, 10, 12], [13, -14, 15], [-16, 17, 19]], [[-19, 20, 21], [1, 2, 3], [-25, 26, 27]]], [[[0, 0, 0], [-3, -15/2, -4], [6, -6, -6]], [[3, 15/2, 4], [0, 0, 0], [-17/2, 15/2, 8]], [[-6, 6, 6], [17/2, -15/2, -8], [0, 0, 0]]]) >>> all(s[i,j,k] == (c[i,j,k]-c[j,i,k])/Integer(2) # Check of the result: ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True >>> s = c.antisymmetrize(Integer(1),Integer(2)) ; s # antisymmetrization on the last two indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (1, 2) >>> c[:], s[:] ([[[-1, -2, 3], [4, -5, 4], [-7, 8, 9]], [[10, 10, 12], [13, -14, 15], [-16, 17, 19]], [[-19, 20, 21], [1, 2, 3], [-25, 26, 27]]], [[[0, -3, 5], [3, 0, -2], [-5, 2, 0]], [[0, -3/2, 14], [3/2, 0, -1], [-14, 1, 0]], [[0, 19/2, 23], [-19/2, 0, -23/2], [-23, 23/2, 0]]]) >>> all(s[i,j,k] == (c[i,j,k]-c[i,k,j])/Integer(2) # Check of the result: ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True >>> s = c.antisymmetrize(Integer(0),Integer(2)) ; s # antisymmetrization on the first and last indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with antisymmetry on the index positions (0, 2) >>> c[:], s[:] ([[[-1, -2, 3], [4, -5, 4], [-7, 8, 9]], [[10, 10, 12], [13, -14, 15], [-16, 17, 19]], [[-19, 20, 21], [1, 2, 3], [-25, 26, 27]]], [[[0, -6, 11], [0, -9, 3/2], [0, 12, 17]], [[6, 0, -4], [9, 0, 13/2], [-12, 0, -7/2]], [[-11, 4, 0], [-3/2, -13/2, 0], [-17, 7/2, 0]]]) >>> all(s[i,j,k] == (c[i,j,k]-c[k,j,i])/Integer(2) # Check of the result: ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True
The order of index positions in the argument does not matter:
sage: c.antisymmetrize(1,0) == c.antisymmetrize(0,1) True sage: c.antisymmetrize(2,1) == c.antisymmetrize(1,2) True sage: c.antisymmetrize(2,0) == c.antisymmetrize(0,2) True
>>> from sage.all import * >>> c.antisymmetrize(Integer(1),Integer(0)) == c.antisymmetrize(Integer(0),Integer(1)) True >>> c.antisymmetrize(Integer(2),Integer(1)) == c.antisymmetrize(Integer(1),Integer(2)) True >>> c.antisymmetrize(Integer(2),Integer(0)) == c.antisymmetrize(Integer(0),Integer(2)) True
- contract(*args)[source]¶
Contraction on one or many indices with another instance of
Components
.INPUT:
pos1
– positions of the indices inself
involved in the contraction;pos1
must be a sequence of integers, with 0 standing for the first index position, 1 for the second one, etc. Ifpos1
is not provided, a single contraction on the last index position ofself
is assumedother
– the set of components to contract withpos2
– positions of the indices inother
involved in the contraction, with the same conventions as forpos1
. Ifpos2
is not provided, a single contraction on the first index position ofother
is assumed
OUTPUT: set of components resulting from the contraction
EXAMPLES:
Contraction of a 1-index set of components with a 2-index one:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ, 3) sage: a = Components(QQ, V.basis(), 1) sage: a[:] = (-1, 2, 3) sage: b = Components(QQ, V.basis(), 2) sage: b[:] = [[1,2,3], [4,5,6], [7,8,9]] sage: s0 = a.contract(0, b, 0) ; s0 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s0[:] [28, 32, 36] sage: s0[:] == [sum(a[j]*b[j,i] for j in range(3)) for i in range(3)] # check True sage: s1 = a.contract(0, b, 1) ; s1[:] [12, 24, 36] sage: s1[:] == [sum(a[j]*b[i,j] for j in range(3)) for i in range(3)] # check True
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ, Integer(3)) >>> a = Components(QQ, V.basis(), Integer(1)) >>> a[:] = (-Integer(1), Integer(2), Integer(3)) >>> b = Components(QQ, V.basis(), Integer(2)) >>> b[:] = [[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]] >>> s0 = a.contract(Integer(0), b, Integer(0)) ; s0 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s0[:] [28, 32, 36] >>> s0[:] == [sum(a[j]*b[j,i] for j in range(Integer(3))) for i in range(Integer(3))] # check True >>> s1 = a.contract(Integer(0), b, Integer(1)) ; s1[:] [12, 24, 36] >>> s1[:] == [sum(a[j]*b[i,j] for j in range(Integer(3))) for i in range(Integer(3))] # check True
Parallel computations (see
Parallelism
):sage: Parallelism().set('tensor', nproc=2) sage: Parallelism().get('tensor') 2 sage: s0_par = a.contract(0, b, 0) ; s0_par 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s0_par[:] [28, 32, 36] sage: s0_par == s0 True sage: s1_par = a.contract(0, b, 1) ; s1_par[:] [12, 24, 36] sage: s1_par == s1 True sage: Parallelism().set('tensor', nproc = 1) # switch off parallelization
>>> from sage.all import * >>> Parallelism().set('tensor', nproc=Integer(2)) >>> Parallelism().get('tensor') 2 >>> s0_par = a.contract(Integer(0), b, Integer(0)) ; s0_par 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s0_par[:] [28, 32, 36] >>> s0_par == s0 True >>> s1_par = a.contract(Integer(0), b, Integer(1)) ; s1_par[:] [12, 24, 36] >>> s1_par == s1 True >>> Parallelism().set('tensor', nproc = Integer(1)) # switch off parallelization
Contraction on 2 indices:
sage: c = a*b ; c 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s = c.contract(1,2, b, 0,1) ; s 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s[:] [-285, 570, 855] sage: [sum(sum(c[i,j,k]*b[j,k] for k in range(3)) # check ....: for j in range(3)) for i in range(3)] [-285, 570, 855]
>>> from sage.all import * >>> c = a*b ; c 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s = c.contract(Integer(1),Integer(2), b, Integer(0),Integer(1)) ; s 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s[:] [-285, 570, 855] >>> [sum(sum(c[i,j,k]*b[j,k] for k in range(Integer(3))) # check ... for j in range(Integer(3))) for i in range(Integer(3))] [-285, 570, 855]
Parallel computation:
sage: Parallelism().set('tensor', nproc=2) sage: c_par = a*b ; c_par 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: c_par == c True sage: s_par = c_par.contract(1,2, b, 0,1) ; s_par 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s_par[:] [-285, 570, 855] sage: s_par == s True sage: Parallelism().set('tensor', nproc=1) # switch off parallelization
>>> from sage.all import * >>> Parallelism().set('tensor', nproc=Integer(2)) >>> c_par = a*b ; c_par 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> c_par == c True >>> s_par = c_par.contract(Integer(1),Integer(2), b, Integer(0),Integer(1)) ; s_par 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s_par[:] [-285, 570, 855] >>> s_par == s True >>> Parallelism().set('tensor', nproc=Integer(1)) # switch off parallelization
Consistency check with
trace()
:sage: b = a*a ; b # the tensor product of a with itself Fully symmetric 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: b[:] [ 1 -2 -3] [-2 4 6] [-3 6 9] sage: b.trace(0,1) 14 sage: a.contract(0, a, 0) == b.trace(0,1) True
>>> from sage.all import * >>> b = a*a ; b # the tensor product of a with itself Fully symmetric 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> b[:] [ 1 -2 -3] [-2 4 6] [-3 6 9] >>> b.trace(Integer(0),Integer(1)) 14 >>> a.contract(Integer(0), a, Integer(0)) == b.trace(Integer(0),Integer(1)) True
- copy()[source]¶
Return an exact copy of
self
.EXAMPLES:
Copy of a set of components with a single index:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) sage: a = Components(QQ, V.basis(), 1) sage: a[:] = -2, 1, 5 sage: b = a.copy() ; b 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: b[:] [-2, 1, 5] sage: b == a True sage: b is a # b is a distinct object False
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ,Integer(3)) >>> a = Components(QQ, V.basis(), Integer(1)) >>> a[:] = -Integer(2), Integer(1), Integer(5) >>> b = a.copy() ; b 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> b[:] [-2, 1, 5] >>> b == a True >>> b is a # b is a distinct object False
- display(symbol, latex_symbol=None, index_positions=None, index_labels=None, index_latex_labels=None, format_spec=None, only_nonzero=True, only_nonredundant=False)[source]¶
Display all the components, one per line.
The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode).
INPUT:
symbol
– string (typically a single letter) specifying the symbol for the componentslatex_symbol
– (default:None
) string specifying the LaTeX symbol for the components; ifNone
,symbol
is usedindex_positions
– (default:None
) string of length the number of indices of the components and composed of characters ‘d’ (for “down”) or ‘u’ (for “up”) to specify the position of each index: ‘d’ corresponds to a subscript and ‘u’ to a superscript. Ifindex_positions
isNone
, all indices are printed as subscriptsindex_labels
– (default:None
) list of strings representing the labels of each of the individual indices within the index range defined at the construction of the object; ifNone
, integer labels are usedindex_latex_labels
– (default:None
) list of strings representing the LaTeX labels of each of the individual indices within the index range defined at the construction of the object; ifNone
, integers labels are usedformat_spec
– (default:None
) format specification passed to the output formatter declared at the construction of the objectonly_nonzero
– boolean (default:True
); ifTrue
, only nonzero components are displayedonly_nonredundant
– boolean (default:False
); ifTrue
, only nonredundant components are displayed in case of symmetries
EXAMPLES:
Display of 3-indices components w.r.t. to the canonical basis of the free module \(\ZZ^2\) over the integer ring:
sage: from sage.tensor.modules.comp import Components sage: c = Components(ZZ, (ZZ^2).basis(), 3) sage: c[0,1,0], c[1,0,1], c[1,1,1] = -2, 5, 3 sage: c.display('c') c_010 = -2 c_101 = 5 c_111 = 3
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> c = Components(ZZ, (ZZ**Integer(2)).basis(), Integer(3)) >>> c[Integer(0),Integer(1),Integer(0)], c[Integer(1),Integer(0),Integer(1)], c[Integer(1),Integer(1),Integer(1)] = -Integer(2), Integer(5), Integer(3) >>> c.display('c') c_010 = -2 c_101 = 5 c_111 = 3
By default, only nonzero components are shown; to display all the components, it suffices to set the parameter
only_nonzero
toFalse
:sage: c.display('c', only_nonzero=False) c_000 = 0 c_001 = 0 c_010 = -2 c_011 = 0 c_100 = 0 c_101 = 5 c_110 = 0 c_111 = 3
>>> from sage.all import * >>> c.display('c', only_nonzero=False) c_000 = 0 c_001 = 0 c_010 = -2 c_011 = 0 c_100 = 0 c_101 = 5 c_110 = 0 c_111 = 3
By default, all indices are printed as subscripts, but any index position can be specified:
sage: c.display('c', index_positions='udd') c^0_10 = -2 c^1_01 = 5 c^1_11 = 3 sage: c.display('c', index_positions='udu') c^0_1^0 = -2 c^1_0^1 = 5 c^1_1^1 = 3 sage: c.display('c', index_positions='ddu') c_01^0 = -2 c_10^1 = 5 c_11^1 = 3
>>> from sage.all import * >>> c.display('c', index_positions='udd') c^0_10 = -2 c^1_01 = 5 c^1_11 = 3 >>> c.display('c', index_positions='udu') c^0_1^0 = -2 c^1_0^1 = 5 c^1_1^1 = 3 >>> c.display('c', index_positions='ddu') c_01^0 = -2 c_10^1 = 5 c_11^1 = 3
The LaTeX output is performed as an array, with the symbol adjustable if it differs from the text symbol:
sage: latex(c.display('c', latex_symbol=r'\Gamma', index_positions='udd')) \begin{array}{lcl} \Gamma_{\phantom{\, 0}\,1\,0}^{\,0\phantom{\, 1}\phantom{\, 0}} & = & -2 \\ \Gamma_{\phantom{\, 1}\,0\,1}^{\,1\phantom{\, 0}\phantom{\, 1}} & = & 5 \\ \Gamma_{\phantom{\, 1}\,1\,1}^{\,1\phantom{\, 1}\phantom{\, 1}} & = & 3 \end{array}
>>> from sage.all import * >>> latex(c.display('c', latex_symbol=r'\Gamma', index_positions='udd')) \begin{array}{lcl} \Gamma_{\phantom{\, 0}\,1\,0}^{\,0\phantom{\, 1}\phantom{\, 0}} & = & -2 \\ \Gamma_{\phantom{\, 1}\,0\,1}^{\,1\phantom{\, 0}\phantom{\, 1}} & = & 5 \\ \Gamma_{\phantom{\, 1}\,1\,1}^{\,1\phantom{\, 1}\phantom{\, 1}} & = & 3 \end{array}
The index labels can differ from integers:
sage: c.display('c', index_labels=['x','y']) c_xyx = -2 c_yxy = 5 c_yyy = 3
>>> from sage.all import * >>> c.display('c', index_labels=['x','y']) c_xyx = -2 c_yxy = 5 c_yyy = 3
If the index labels are longer than a single character, they are separated by a comma:
sage: c.display('c', index_labels=['r', 'th']) c_r,th,r = -2 c_th,r,th = 5 c_th,th,th = 3
>>> from sage.all import * >>> c.display('c', index_labels=['r', 'th']) c_r,th,r = -2 c_th,r,th = 5 c_th,th,th = 3
The LaTeX labels for the indices can be specified if they differ from the text ones:
sage: c.display('c', index_labels=['r', 'th'], ....: index_latex_labels=['r', r'\theta']) c_r,th,r = -2 c_th,r,th = 5 c_th,th,th = 3
>>> from sage.all import * >>> c.display('c', index_labels=['r', 'th'], ... index_latex_labels=['r', r'\theta']) c_r,th,r = -2 c_th,r,th = 5 c_th,th,th = 3
The display of components with symmetries is governed by the parameter
only_nonredundant
:sage: from sage.tensor.modules.comp import CompWithSym sage: c = CompWithSym(ZZ, (ZZ^2).basis(), 3, sym=(1,2)) ; c 3-indices components w.r.t. [ (1, 0), (0, 1) ], with symmetry on the index positions (1, 2) sage: c[0,0,1] = 2 sage: c.display('c') c_001 = 2 c_010 = 2 sage: c.display('c', only_nonredundant=True) c_001 = 2
>>> from sage.all import * >>> from sage.tensor.modules.comp import CompWithSym >>> c = CompWithSym(ZZ, (ZZ**Integer(2)).basis(), Integer(3), sym=(Integer(1),Integer(2))) ; c 3-indices components w.r.t. [ (1, 0), (0, 1) ], with symmetry on the index positions (1, 2) >>> c[Integer(0),Integer(0),Integer(1)] = Integer(2) >>> c.display('c') c_001 = 2 c_010 = 2 >>> c.display('c', only_nonredundant=True) c_001 = 2
If some nontrivial output formatter has been set, the format can be specified by means of the argument
format_spec
:sage: c = Components(QQ, (QQ^3).basis(), 2, ....: output_formatter=Rational.numerical_approx) sage: c[0,1] = 1/3 sage: c[2,1] = 2/7 sage: c.display('C') # default format (53 bits of precision) C_01 = 0.333333333333333 C_21 = 0.285714285714286 sage: c.display('C', format_spec=10) # 10 bits of precision C_01 = 0.33 C_21 = 0.29
>>> from sage.all import * >>> c = Components(QQ, (QQ**Integer(3)).basis(), Integer(2), ... output_formatter=Rational.numerical_approx) >>> c[Integer(0),Integer(1)] = Integer(1)/Integer(3) >>> c[Integer(2),Integer(1)] = Integer(2)/Integer(7) >>> c.display('C') # default format (53 bits of precision) C_01 = 0.333333333333333 C_21 = 0.285714285714286 >>> c.display('C', format_spec=Integer(10)) # 10 bits of precision C_01 = 0.33 C_21 = 0.29
Check that the bug reported in Issue #22520 is fixed:
sage: c = Components(SR, [1, 2], 1) # needs sage.symbolic sage: c[0] = SR.var('t', domain='real') # needs sage.symbolic sage: c.display('c') # needs sage.symbolic c_0 = t
>>> from sage.all import * >>> c = Components(SR, [Integer(1), Integer(2)], Integer(1)) # needs sage.symbolic >>> c[Integer(0)] = SR.var('t', domain='real') # needs sage.symbolic >>> c.display('c') # needs sage.symbolic c_0 = t
- index_generator()[source]¶
Generator of indices.
OUTPUT: an iterable index
EXAMPLES:
Indices on a 3-dimensional vector space:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) sage: c = Components(QQ, V.basis(), 1) sage: list(c.index_generator()) [(0,), (1,), (2,)] sage: c = Components(QQ, V.basis(), 1, start_index=1) sage: list(c.index_generator()) [(1,), (2,), (3,)] sage: c = Components(QQ, V.basis(), 2) sage: list(c.index_generator()) [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ,Integer(3)) >>> c = Components(QQ, V.basis(), Integer(1)) >>> list(c.index_generator()) [(0,), (1,), (2,)] >>> c = Components(QQ, V.basis(), Integer(1), start_index=Integer(1)) >>> list(c.index_generator()) [(1,), (2,), (3,)] >>> c = Components(QQ, V.basis(), Integer(2)) >>> list(c.index_generator()) [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
- is_zero()[source]¶
Return
True
if all the components are zero andFalse
otherwise.EXAMPLES:
A just-created set of components is initialized to zero:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) sage: c = Components(QQ, V.basis(), 1) sage: c.is_zero() True sage: c[:] [0, 0, 0] sage: c[0] = 1 ; c[:] [1, 0, 0] sage: c.is_zero() False sage: c[0] = 0 ; c[:] [0, 0, 0] sage: c.is_zero() True
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ,Integer(3)) >>> c = Components(QQ, V.basis(), Integer(1)) >>> c.is_zero() True >>> c[:] [0, 0, 0] >>> c[Integer(0)] = Integer(1) ; c[:] [1, 0, 0] >>> c.is_zero() False >>> c[Integer(0)] = Integer(0) ; c[:] [0, 0, 0] >>> c.is_zero() True
It is equivalent to use the operator == to compare to zero:
sage: c == 0 True sage: c != 0 False
>>> from sage.all import * >>> c == Integer(0) True >>> c != Integer(0) False
Comparing to a nonzero number is meaningless:
sage: c == 1 Traceback (most recent call last): ... TypeError: cannot compare a set of components to a number
>>> from sage.all import * >>> c == Integer(1) Traceback (most recent call last): ... TypeError: cannot compare a set of components to a number
- items()[source]¶
Return an iterable of
(indices, value)
elements.This may (but is not guaranteed to) suppress zero values.
EXAMPLES:
sage: from sage.tensor.modules.comp import Components, CompWithSym sage: c = Components(ZZ, (ZZ^2).basis(), 3) sage: c[0,1,0], c[1,0,1], c[1,1,1] = -2, 5, 3 sage: list(c.items()) [((0, 1, 0), -2), ((1, 0, 1), 5), ((1, 1, 1), 3)] sage: c = CompWithSym(ZZ, (ZZ^2).basis(), 3, sym=((1, 2))) sage: c[0,1,0], c[1,0,1], c[1,1,1] = -2, 5, 3 sage: list(c.items()) [((0, 0, 1), -2), ((0, 1, 0), -2), ((1, 0, 1), 5), ((1, 1, 0), 5), ((1, 1, 1), 3)]
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components, CompWithSym >>> c = Components(ZZ, (ZZ**Integer(2)).basis(), Integer(3)) >>> c[Integer(0),Integer(1),Integer(0)], c[Integer(1),Integer(0),Integer(1)], c[Integer(1),Integer(1),Integer(1)] = -Integer(2), Integer(5), Integer(3) >>> list(c.items()) [((0, 1, 0), -2), ((1, 0, 1), 5), ((1, 1, 1), 3)] >>> c = CompWithSym(ZZ, (ZZ**Integer(2)).basis(), Integer(3), sym=((Integer(1), Integer(2)))) >>> c[Integer(0),Integer(1),Integer(0)], c[Integer(1),Integer(0),Integer(1)], c[Integer(1),Integer(1),Integer(1)] = -Integer(2), Integer(5), Integer(3) >>> list(c.items()) [((0, 0, 1), -2), ((0, 1, 0), -2), ((1, 0, 1), 5), ((1, 1, 0), 5), ((1, 1, 1), 3)]
- non_redundant_index_generator()[source]¶
Generator of non redundant indices.
In the absence of declared symmetries, all possible indices are generated. So this method is equivalent to
index_generator()
. Only versions for derived classes with symmetries or antisymmetries are not trivial.OUTPUT: an iterable index
EXAMPLES:
Indices on a 3-dimensional vector space:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) sage: c = Components(QQ, V.basis(), 2) sage: list(c.non_redundant_index_generator()) [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] sage: c = Components(QQ, V.basis(), 2, start_index=1) sage: list(c.non_redundant_index_generator()) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ,Integer(3)) >>> c = Components(QQ, V.basis(), Integer(2)) >>> list(c.non_redundant_index_generator()) [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] >>> c = Components(QQ, V.basis(), Integer(2), start_index=Integer(1)) >>> list(c.non_redundant_index_generator()) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
- swap_adjacent_indices(pos1, pos2, pos3)[source]¶
Swap two adjacent sets of indices.
This method is essentially required to reorder the covariant and contravariant indices in the computation of a tensor product.
INPUT:
pos1
– position of the first index of set 1 (with the conventionposition=0
for the first slot)pos2
– position of the first index of set 2 equals 1 plus the position of the last index of set 1 (since the two sets are adjacent)pos3
– 1 plus position of the last index of set 2
OUTPUT: components with index set 1 permuted with index set 2
EXAMPLES:
Swap of the two indices of a 2-indices set of components:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ, 3) sage: c = Components(QQ, V.basis(), 2) sage: c[:] = [[1,2,3], [4,5,6], [7,8,9]] sage: c1 = c.swap_adjacent_indices(0,1,2) sage: c[:], c1[:] ( [1 2 3] [1 4 7] [4 5 6] [2 5 8] [7 8 9], [3 6 9] )
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ, Integer(3)) >>> c = Components(QQ, V.basis(), Integer(2)) >>> c[:] = [[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]] >>> c1 = c.swap_adjacent_indices(Integer(0),Integer(1),Integer(2)) >>> c[:], c1[:] ( [1 2 3] [1 4 7] [4 5 6] [2 5 8] [7 8 9], [3 6 9] )
Swap of two pairs of indices on a 4-indices set of components:
sage: d = c*c1 ; d 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: d1 = d.swap_adjacent_indices(0,2,4) sage: d[0,1,1,2] 16 sage: d1[1,2,0,1] 16 sage: d1[0,1,1,2] 24 sage: d[1,2,0,1] 24
>>> from sage.all import * >>> d = c*c1 ; d 4-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> d1 = d.swap_adjacent_indices(Integer(0),Integer(2),Integer(4)) >>> d[Integer(0),Integer(1),Integer(1),Integer(2)] 16 >>> d1[Integer(1),Integer(2),Integer(0),Integer(1)] 16 >>> d1[Integer(0),Integer(1),Integer(1),Integer(2)] 24 >>> d[Integer(1),Integer(2),Integer(0),Integer(1)] 24
- symmetrize(*pos)[source]¶
Symmetrization over the given index positions.
INPUT:
pos
– list of index positions involved in the symmetrization (with the convention position=0 for the first slot); if none, the symmetrization is performed over all the indices
OUTPUT:
an instance of
CompWithSym
describing the symmetrized components
EXAMPLES:
Symmetrization of 2-indices components:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ, 3) sage: c = Components(QQ, V.basis(), 2) sage: c[:] = [[1,2,3], [4,5,6], [7,8,9]] sage: s = c.symmetrize() ; s Fully symmetric 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: c[:], s[:] ( [1 2 3] [1 3 5] [4 5 6] [3 5 7] [7 8 9], [5 7 9] ) sage: c.symmetrize() == c.symmetrize(0,1) True
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ, Integer(3)) >>> c = Components(QQ, V.basis(), Integer(2)) >>> c[:] = [[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]] >>> s = c.symmetrize() ; s Fully symmetric 2-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> c[:], s[:] ( [1 2 3] [1 3 5] [4 5 6] [3 5 7] [7 8 9], [5 7 9] ) >>> c.symmetrize() == c.symmetrize(Integer(0),Integer(1)) True
Full symmetrization of 3-indices components:
sage: c = Components(QQ, V.basis(), 3) sage: c[:] = [[[1,2,3], [4,5,6], [7,8,9]], [[10,11,12], [13,14,15], [16,17,18]], [[19,20,21], [22,23,24], [25,26,27]]] sage: s = c.symmetrize() ; s Fully symmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: c[:], s[:] ([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]], [[[1, 16/3, 29/3], [16/3, 29/3, 14], [29/3, 14, 55/3]], [[16/3, 29/3, 14], [29/3, 14, 55/3], [14, 55/3, 68/3]], [[29/3, 14, 55/3], [14, 55/3, 68/3], [55/3, 68/3, 27]]]) sage: all(s[i,j,k] == (c[i,j,k]+c[i,k,j]+c[j,k,i]+c[j,i,k]+c[k,i,j]+c[k,j,i])/6 # Check of the result: ....: for i in range(3) for j in range(3) for k in range(3)) True sage: c.symmetrize() == c.symmetrize(0,1,2) True
>>> from sage.all import * >>> c = Components(QQ, V.basis(), Integer(3)) >>> c[:] = [[[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], [[Integer(10),Integer(11),Integer(12)], [Integer(13),Integer(14),Integer(15)], [Integer(16),Integer(17),Integer(18)]], [[Integer(19),Integer(20),Integer(21)], [Integer(22),Integer(23),Integer(24)], [Integer(25),Integer(26),Integer(27)]]] >>> s = c.symmetrize() ; s Fully symmetric 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> c[:], s[:] ([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]], [[[1, 16/3, 29/3], [16/3, 29/3, 14], [29/3, 14, 55/3]], [[16/3, 29/3, 14], [29/3, 14, 55/3], [14, 55/3, 68/3]], [[29/3, 14, 55/3], [14, 55/3, 68/3], [55/3, 68/3, 27]]]) >>> all(s[i,j,k] == (c[i,j,k]+c[i,k,j]+c[j,k,i]+c[j,i,k]+c[k,i,j]+c[k,j,i])/Integer(6) # Check of the result: ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True >>> c.symmetrize() == c.symmetrize(Integer(0),Integer(1),Integer(2)) True
Partial symmetrization of 3-indices components:
sage: s = c.symmetrize(0,1) ; s # symmetrization on the first two indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) sage: c[:], s[:] ([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]], [[[1, 2, 3], [7, 8, 9], [13, 14, 15]], [[7, 8, 9], [13, 14, 15], [19, 20, 21]], [[13, 14, 15], [19, 20, 21], [25, 26, 27]]]) sage: all(s[i,j,k] == (c[i,j,k]+c[j,i,k])/2 # Check of the result: ....: for i in range(3) for j in range(3) for k in range(3)) True sage: s = c.symmetrize(1,2) ; s # symmetrization on the last two indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2) sage: c[:], s[:] ([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]], [[[1, 3, 5], [3, 5, 7], [5, 7, 9]], [[10, 12, 14], [12, 14, 16], [14, 16, 18]], [[19, 21, 23], [21, 23, 25], [23, 25, 27]]]) sage: all(s[i,j,k] == (c[i,j,k]+c[i,k,j])/2 # Check of the result: ....: for i in range(3) for j in range(3) for k in range(3)) True sage: s = c.symmetrize(0,2) ; s # symmetrization on the first and last indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 2) sage: c[:], s[:] ([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]], [[[1, 6, 11], [4, 9, 14], [7, 12, 17]], [[6, 11, 16], [9, 14, 19], [12, 17, 22]], [[11, 16, 21], [14, 19, 24], [17, 22, 27]]]) sage: all(s[i,j,k] == (c[i,j,k]+c[k,j,i])/2 # Check of the result: ....: for i in range(3) for j in range(3) for k in range(3)) True
>>> from sage.all import * >>> s = c.symmetrize(Integer(0),Integer(1)) ; s # symmetrization on the first two indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 1) >>> c[:], s[:] ([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]], [[[1, 2, 3], [7, 8, 9], [13, 14, 15]], [[7, 8, 9], [13, 14, 15], [19, 20, 21]], [[13, 14, 15], [19, 20, 21], [25, 26, 27]]]) >>> all(s[i,j,k] == (c[i,j,k]+c[j,i,k])/Integer(2) # Check of the result: ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True >>> s = c.symmetrize(Integer(1),Integer(2)) ; s # symmetrization on the last two indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (1, 2) >>> c[:], s[:] ([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]], [[[1, 3, 5], [3, 5, 7], [5, 7, 9]], [[10, 12, 14], [12, 14, 16], [14, 16, 18]], [[19, 21, 23], [21, 23, 25], [23, 25, 27]]]) >>> all(s[i,j,k] == (c[i,j,k]+c[i,k,j])/Integer(2) # Check of the result: ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True >>> s = c.symmetrize(Integer(0),Integer(2)) ; s # symmetrization on the first and last indices 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ], with symmetry on the index positions (0, 2) >>> c[:], s[:] ([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]], [[[1, 6, 11], [4, 9, 14], [7, 12, 17]], [[6, 11, 16], [9, 14, 19], [12, 17, 22]], [[11, 16, 21], [14, 19, 24], [17, 22, 27]]]) >>> all(s[i,j,k] == (c[i,j,k]+c[k,j,i])/Integer(2) # Check of the result: ... for i in range(Integer(3)) for j in range(Integer(3)) for k in range(Integer(3))) True
- trace(pos1, pos2)[source]¶
Index contraction.
INPUT:
pos1
– position of the first index for the contraction (with the convention position=0 for the first slot)pos2
– position of the second index for the contraction
OUTPUT:
set of components resulting from the (pos1, pos2) contraction
EXAMPLES:
Self-contraction of a set of components with 2 indices:
sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ, 3) sage: c = Components(QQ, V.basis(), 2) sage: c[:] = [[1,2,3], [4,5,6], [7,8,9]] sage: c.trace(0,1) 15 sage: c[0,0] + c[1,1] + c[2,2] # check 15
>>> from sage.all import * >>> from sage.tensor.modules.comp import Components >>> V = VectorSpace(QQ, Integer(3)) >>> c = Components(QQ, V.basis(), Integer(2)) >>> c[:] = [[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]] >>> c.trace(Integer(0),Integer(1)) 15 >>> c[Integer(0),Integer(0)] + c[Integer(1),Integer(1)] + c[Integer(2),Integer(2)] # check 15
Three self-contractions of a set of components with 3 indices:
sage: v = Components(QQ, V.basis(), 1) sage: v[:] = (-1,2,3) sage: a = c*v ; a 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s = a.trace(0,1) ; s # contraction on the first two indices 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] sage: s[:] [-15, 30, 45] sage: [sum(a[j,j,i] for j in range(3)) for i in range(3)] # check [-15, 30, 45] sage: s = a.trace(0,2) ; s[:] # contraction on the first and last indices [28, 32, 36] sage: [sum(a[j,i,j] for j in range(3)) for i in range(3)] # check [28, 32, 36] sage: s = a.trace(1,2) ; s[:] # contraction on the last two indices [12, 24, 36] sage: [sum(a[i,j,j] for j in range(3)) for i in range(3)] # check [12, 24, 36]
>>> from sage.all import * >>> v = Components(QQ, V.basis(), Integer(1)) >>> v[:] = (-Integer(1),Integer(2),Integer(3)) >>> a = c*v ; a 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s = a.trace(Integer(0),Integer(1)) ; s # contraction on the first two indices 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] >>> s[:] [-15, 30, 45] >>> [sum(a[j,j,i] for j in range(Integer(3))) for i in range(Integer(3))] # check [-15, 30, 45] >>> s = a.trace(Integer(0),Integer(2)) ; s[:] # contraction on the first and last indices [28, 32, 36] >>> [sum(a[j,i,j] for j in range(Integer(3))) for i in range(Integer(3))] # check [28, 32, 36] >>> s = a.trace(Integer(1),Integer(2)) ; s[:] # contraction on the last two indices [12, 24, 36] >>> [sum(a[i,j,j] for j in range(Integer(3))) for i in range(Integer(3))] # check [12, 24, 36]
- class sage.tensor.modules.comp.KroneckerDelta(ring, frame, start_index=0, output_formatter=None)[source]¶
Bases:
CompFullySym
Kronecker delta \(\delta_{ij}\).
INPUT:
ring
– commutative ring in which each component takes its valueframe
– frame with respect to which the components are defined; whatever typeframe
is, it should have some method__len__()
implemented, so thatlen(frame)
returns the dimension, i.e. the size of a single index rangestart_index
– (default: 0) first value of a single index; accordingly a component index i must obeystart_index <= i <= start_index + dim - 1
, wheredim = len(frame)
.output_formatter
– (default:None
) function or unbound method called to format the output of the component access operator[...]
(method__getitem__
);output_formatter
must take 1 or 2 arguments: the first argument must be an instance ofring
and the second one, if any, some format specification
EXAMPLES:
The Kronecker delta on a 3-dimensional space:
sage: from sage.tensor.modules.comp import KroneckerDelta sage: V = VectorSpace(QQ,3) sage: d = KroneckerDelta(QQ, V.basis()) ; d Kronecker delta of size 3x3 sage: d[:] [1 0 0] [0 1 0] [0 0 1]
>>> from sage.all import * >>> from sage.tensor.modules.comp import KroneckerDelta >>> V = VectorSpace(QQ,Integer(3)) >>> d = KroneckerDelta(QQ, V.basis()) ; d Kronecker delta of size 3x3 >>> d[:] [1 0 0] [0 1 0] [0 0 1]
One can read, but not set, the components of a Kronecker delta:
sage: d[1,1] 1 sage: d[1,1] = 2 Traceback (most recent call last): ... TypeError: the components of a Kronecker delta cannot be changed
>>> from sage.all import * >>> d[Integer(1),Integer(1)] 1 >>> d[Integer(1),Integer(1)] = Integer(2) Traceback (most recent call last): ... TypeError: the components of a Kronecker delta cannot be changed
Examples of use with output formatters:
sage: d = KroneckerDelta(QQ, V.basis(), output_formatter=Rational.numerical_approx) sage: d[:] # default format (53 bits of precision) [ 1.00000000000000 0.000000000000000 0.000000000000000] [0.000000000000000 1.00000000000000 0.000000000000000] [0.000000000000000 0.000000000000000 1.00000000000000] sage: d[:,10] # format = 10 bits of precision [ 1.0 0.00 0.00] [0.00 1.0 0.00] [0.00 0.00 1.0] sage: d = KroneckerDelta(QQ, V.basis(), output_formatter=str) sage: d[:] [['1', '0', '0'], ['0', '1', '0'], ['0', '0', '1']]
>>> from sage.all import * >>> d = KroneckerDelta(QQ, V.basis(), output_formatter=Rational.numerical_approx) >>> d[:] # default format (53 bits of precision) [ 1.00000000000000 0.000000000000000 0.000000000000000] [0.000000000000000 1.00000000000000 0.000000000000000] [0.000000000000000 0.000000000000000 1.00000000000000] >>> d[:,Integer(10)] # format = 10 bits of precision [ 1.0 0.00 0.00] [0.00 1.0 0.00] [0.00 0.00 1.0] >>> d = KroneckerDelta(QQ, V.basis(), output_formatter=str) >>> d[:] [['1', '0', '0'], ['0', '1', '0'], ['0', '0', '1']]