Helper classes to implement tensor operations¶
Warning
This module is not meant to be used directly. It just provides functionality for other classes to implement tensor operations.
The VectorCollection
constructs the basis of tensor products
(and symmetric/exterior powers) in terms of a chosen collection of
vectors that generate the vector space(s).
EXAMPLES:
sage: from sage.modules.tensor_operations import VectorCollection, TensorOperation
sage: V = VectorCollection([(1,0), (-1, 0), (1,2)], QQ, 2)
sage: W = VectorCollection([(1,1), (1,-1), (-1, 1)], QQ, 2)
sage: VW = TensorOperation([V, W], operation='product')
>>> from sage.all import *
>>> from sage.modules.tensor_operations import VectorCollection, TensorOperation
>>> V = VectorCollection([(Integer(1),Integer(0)), (-Integer(1), Integer(0)), (Integer(1),Integer(2))], QQ, Integer(2))
>>> W = VectorCollection([(Integer(1),Integer(1)), (Integer(1),-Integer(1)), (-Integer(1), Integer(1))], QQ, Integer(2))
>>> VW = TensorOperation([V, W], operation='product')
Here is the tensor product of two vectors:
sage: V.vectors()[0]
(1, 0)
sage: W.vectors()[1]
(1, -1)
>>> from sage.all import *
>>> V.vectors()[Integer(0)]
(1, 0)
>>> W.vectors()[Integer(1)]
(1, -1)
In a convenient choice of basis, the tensor product is
\((a,b)\otimes(c,d)=(ac,ad,bc,bd)\). In this example, it is one of the
vectors of the vector collection VW
sage: VW.index_map(0, 1)
1
sage: VW.vectors()[VW.index_map(0, 1)]
(1, -1, 0, 0)
sage: rows = []
sage: for i, j in cartesian_product((range(3), range(3))):
....: v = V.vectors()[i]
....: w = W.vectors()[j]
....: i_tensor_j = VW.index_map(i, j)
....: vw = VW.vectors()[i_tensor_j]
....: rows.append([i, v, j, w, i_tensor_j, vw])
sage: table(rows)
0 (1, 0) 0 (1, 1) 0 (1, 1, 0, 0)
0 (1, 0) 1 (1, -1) 1 (1, -1, 0, 0)
0 (1, 0) 2 (-1, 1) 2 (-1, 1, 0, 0)
1 (-1, 0) 0 (1, 1) 3 (-1, -1, 0, 0)
1 (-1, 0) 1 (1, -1) 2 (-1, 1, 0, 0)
1 (-1, 0) 2 (-1, 1) 1 (1, -1, 0, 0)
2 (1, 2) 0 (1, 1) 4 (1, 1, 2, 2)
2 (1, 2) 1 (1, -1) 5 (1, -1, 2, -2)
2 (1, 2) 2 (-1, 1) 6 (-1, 1, -2, 2)
>>> from sage.all import *
>>> VW.index_map(Integer(0), Integer(1))
1
>>> VW.vectors()[VW.index_map(Integer(0), Integer(1))]
(1, -1, 0, 0)
>>> rows = []
>>> for i, j in cartesian_product((range(Integer(3)), range(Integer(3)))):
... v = V.vectors()[i]
... w = W.vectors()[j]
... i_tensor_j = VW.index_map(i, j)
... vw = VW.vectors()[i_tensor_j]
... rows.append([i, v, j, w, i_tensor_j, vw])
>>> table(rows)
0 (1, 0) 0 (1, 1) 0 (1, 1, 0, 0)
0 (1, 0) 1 (1, -1) 1 (1, -1, 0, 0)
0 (1, 0) 2 (-1, 1) 2 (-1, 1, 0, 0)
1 (-1, 0) 0 (1, 1) 3 (-1, -1, 0, 0)
1 (-1, 0) 1 (1, -1) 2 (-1, 1, 0, 0)
1 (-1, 0) 2 (-1, 1) 1 (1, -1, 0, 0)
2 (1, 2) 0 (1, 1) 4 (1, 1, 2, 2)
2 (1, 2) 1 (1, -1) 5 (1, -1, 2, -2)
2 (1, 2) 2 (-1, 1) 6 (-1, 1, -2, 2)
- class sage.modules.tensor_operations.TensorOperation(vector_collections, operation='product')[source]¶
Bases:
VectorCollection
Auxiliary class to compute the tensor product of two
VectorCollection
objects.Warning
This class is only used as a base class for filtered vector spaces. You should not use it yourself.
INPUT:
vector_collections
– a nonempty list/tuple/iterable ofVectorCollection
objectsoperation
– string; the tensor operation. Currently allowed values are'product'
,'symmetric'
, and'antisymmetric'
.
Todo
More general tensor operations (specified by Young tableaux) should be implemented.
EXAMPLES:
sage: from sage.modules.tensor_operations import VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (1,2), (-1,-2)], QQ, 2) sage: S = VectorCollection([(1,), (-1,)], QQ, 1) sage: R_tensor_S = TensorOperation([R, S]) sage: R_tensor_S.index_map(0, 0) 0 sage: matrix(ZZ, 3, 2, lambda i,j: R_tensor_S.index_map(i, j)) [0 1] [2 3] [3 2] sage: R_tensor_S.vectors() ((1, 0), (-1, 0), (1, 2), (-1, -2))
>>> from sage.all import * >>> from sage.modules.tensor_operations import VectorCollection, TensorOperation >>> R = VectorCollection([(Integer(1),Integer(0)), (Integer(1),Integer(2)), (-Integer(1),-Integer(2))], QQ, Integer(2)) >>> S = VectorCollection([(Integer(1),), (-Integer(1),)], QQ, Integer(1)) >>> R_tensor_S = TensorOperation([R, S]) >>> R_tensor_S.index_map(Integer(0), Integer(0)) 0 >>> matrix(ZZ, Integer(3), Integer(2), lambda i,j: R_tensor_S.index_map(i, j)) [0 1] [2 3] [3 2] >>> R_tensor_S.vectors() ((1, 0), (-1, 0), (1, 2), (-1, -2))
- codomain()[source]¶
The codomain of the index map.
OUTPUT: list of integers; the image of
index_map()
EXAMPLES:
sage: from sage.modules.tensor_operations import ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (0,1), (-2,-3)], QQ, 2) sage: detR = TensorOperation([R]*2, 'antisymmetric') # needs sage.groups sage: sorted(detR.preimage()) # needs sage.groups [(0, 1), (0, 2), (1, 2)] sage: sorted(detR.codomain()) # needs sage.groups [0, 1, 2]
>>> from sage.all import * >>> from sage.modules.tensor_operations import Ellipsis.: VectorCollection, TensorOperation >>> R = VectorCollection([(Integer(1),Integer(0)), (Integer(0),Integer(1)), (-Integer(2),-Integer(3))], QQ, Integer(2)) >>> detR = TensorOperation([R]*Integer(2), 'antisymmetric') # needs sage.groups >>> sorted(detR.preimage()) # needs sage.groups [(0, 1), (0, 2), (1, 2)] >>> sorted(detR.codomain()) # needs sage.groups [0, 1, 2]
- index_map(*i)[source]¶
Return the result of the tensor operation.
INPUT:
*i
– list of integers. The indices (in the corresponding factor of the tensor operation) of the domain vector.
OUTPUT:
The index (in
vectors()
) of the image of the tensor product/operation acting on the domain vectors indexed by \(i\).None
is returned if the tensor operation maps the generators to zero (usually because of antisymmetry).EXAMPLES:
sage: from sage.modules.tensor_operations import ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (1,2), (-1,-2)], QQ, 2) sage: Sym3_R = TensorOperation([R]*3, 'symmetric')
>>> from sage.all import * >>> from sage.modules.tensor_operations import Ellipsis.: VectorCollection, TensorOperation >>> R = VectorCollection([(Integer(1),Integer(0)), (Integer(1),Integer(2)), (-Integer(1),-Integer(2))], QQ, Integer(2)) >>> Sym3_R = TensorOperation([R]*Integer(3), 'symmetric')
The symmetric product of the first vector
(1,0)
, the second vector(1,2)
, and the third vector(-1,-2)
equals the vector with index number 4 (that is, the fifth) in the symmetric product vector collection:sage: Sym3_R.index_map(0, 1, 2) 4
>>> from sage.all import * >>> Sym3_R.index_map(Integer(0), Integer(1), Integer(2)) 4
In suitable coordinates, this is the vector:
sage: Sym3_R.vectors()[4] (-1, -4, -4, 0)
>>> from sage.all import * >>> Sym3_R.vectors()[Integer(4)] (-1, -4, -4, 0)
The product is symmetric:
sage: Sym3_R.index_map(2, 0, 1) 4 sage: Sym3_R.index_map(2, 1, 0) 4
>>> from sage.all import * >>> Sym3_R.index_map(Integer(2), Integer(0), Integer(1)) 4 >>> Sym3_R.index_map(Integer(2), Integer(1), Integer(0)) 4
As another example, here is the rank-2 determinant:
sage: from sage.modules.tensor_operations import ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (0,1), (-2,-3)], QQ, 2) sage: detR = TensorOperation([R]*2, 'antisymmetric') # needs sage.groups sage: detR.index_map(1, 0) # needs sage.groups 0 sage: detR.index_map(0, 1) # needs sage.groups 0
>>> from sage.all import * >>> from sage.modules.tensor_operations import Ellipsis.: VectorCollection, TensorOperation >>> R = VectorCollection([(Integer(1),Integer(0)), (Integer(0),Integer(1)), (-Integer(2),-Integer(3))], QQ, Integer(2)) >>> detR = TensorOperation([R]*Integer(2), 'antisymmetric') # needs sage.groups >>> detR.index_map(Integer(1), Integer(0)) # needs sage.groups 0 >>> detR.index_map(Integer(0), Integer(1)) # needs sage.groups 0
- preimage()[source]¶
A choice of pre-image multi-indices.
OUTPUT:
A list of multi-indices (tuples of integers) whose image is the entire image under the
index_map()
.EXAMPLES:
sage: from sage.modules.tensor_operations import ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (0,1), (-2,-3)], QQ, 2) sage: detR = TensorOperation([R]*2, 'antisymmetric') # needs sage.groups sage: sorted(detR.preimage()) # needs sage.groups [(0, 1), (0, 2), (1, 2)] sage: sorted(detR.codomain()) # needs sage.groups [0, 1, 2]
>>> from sage.all import * >>> from sage.modules.tensor_operations import Ellipsis.: VectorCollection, TensorOperation >>> R = VectorCollection([(Integer(1),Integer(0)), (Integer(0),Integer(1)), (-Integer(2),-Integer(3))], QQ, Integer(2)) >>> detR = TensorOperation([R]*Integer(2), 'antisymmetric') # needs sage.groups >>> sorted(detR.preimage()) # needs sage.groups [(0, 1), (0, 2), (1, 2)] >>> sorted(detR.codomain()) # needs sage.groups [0, 1, 2]
- class sage.modules.tensor_operations.VectorCollection(vector_collection, base_ring, dim)[source]¶
Bases:
FreeModule_ambient_field
An ordered collection of generators of a vector space.
This is like a list of vectors, but with extra argument checking.
Warning
This class is only used as a base class for filtered vector spaces. You should not use it yourself.
INPUT:
dim
– integer; the dimension of the ambient vector spacebase_ring
– a field; the base field of the ambient vector spacerays
– any list/iterable of things than can be converted into vectors of the ambient vector space. These will be used to span the subspaces of the filtration. Must span the ambient vector space.
EXAMPLES:
sage: from sage.modules.tensor_operations import VectorCollection sage: R = VectorCollection([(1,0), (0,1), (1,2)], QQ, 2); R Vector space of dimension 2 over Rational Field
>>> from sage.all import * >>> from sage.modules.tensor_operations import VectorCollection >>> R = VectorCollection([(Integer(1),Integer(0)), (Integer(0),Integer(1)), (Integer(1),Integer(2))], QQ, Integer(2)); R Vector space of dimension 2 over Rational Field
- n_vectors()[source]¶
Return the number of vectors.
OUTPUT: integer
EXAMPLES:
sage: from sage.modules.tensor_operations import VectorCollection sage: V = VectorCollection([(1,0), (0,1), (1,2)], QQ, 2) sage: V.n_vectors() 3
>>> from sage.all import * >>> from sage.modules.tensor_operations import VectorCollection >>> V = VectorCollection([(Integer(1),Integer(0)), (Integer(0),Integer(1)), (Integer(1),Integer(2))], QQ, Integer(2)) >>> V.n_vectors() 3
- vectors()[source]¶
Return the collection of vectors.
OUTPUT:
A tuple of vectors. The vectors that were specified in the constructor, in the same order.
EXAMPLES:
sage: from sage.modules.tensor_operations import VectorCollection sage: V = VectorCollection([(1,0), (0,1), (1,2)], QQ, 2) sage: V.vectors() ((1, 0), (0, 1), (1, 2))
>>> from sage.all import * >>> from sage.modules.tensor_operations import VectorCollection >>> V = VectorCollection([(Integer(1),Integer(0)), (Integer(0),Integer(1)), (Integer(1),Integer(2))], QQ, Integer(2)) >>> V.vectors() ((1, 0), (0, 1), (1, 2))
- sage.modules.tensor_operations.antisymmetrized_coordinate_sums(dim, n)[source]¶
Return formal anti-symmetrized sum of multi-indices.
INPUT:
dim
– integer; the dimension (range of each index)n
– integer; the total number of indices
OUTPUT:
An anti-symmetrized formal sum of multi-indices (tuples of integers)
EXAMPLES:
sage: from sage.modules.tensor_operations import antisymmetrized_coordinate_sums sage: antisymmetrized_coordinate_sums(3, 2) # needs sage.groups ((0, 1) - (1, 0), (0, 2) - (2, 0), (1, 2) - (2, 1))
>>> from sage.all import * >>> from sage.modules.tensor_operations import antisymmetrized_coordinate_sums >>> antisymmetrized_coordinate_sums(Integer(3), Integer(2)) # needs sage.groups ((0, 1) - (1, 0), (0, 2) - (2, 0), (1, 2) - (2, 1))
- sage.modules.tensor_operations.symmetrized_coordinate_sums(dim, n)[source]¶
Return formal symmetrized sum of multi-indices.
INPUT:
dim
– integer; the dimension (range of each index)n
– integer; the total number of indices
OUTPUT:
A symmetrized formal sum of multi-indices (tuples of integers)
EXAMPLES:
sage: from sage.modules.tensor_operations import symmetrized_coordinate_sums sage: symmetrized_coordinate_sums(2, 2) ((0, 0), (0, 1) + (1, 0), (1, 1))
>>> from sage.all import * >>> from sage.modules.tensor_operations import symmetrized_coordinate_sums >>> symmetrized_coordinate_sums(Integer(2), Integer(2)) ((0, 0), (0, 1) + (1, 0), (1, 1))