Tensors
Type hierarchy
The abstract supertype of all tensors in TensorKit is given by AbstractTensorMap:
TensorKit.AbstractTensorMap — Typeabstract type AbstractTensorMap{T<:Number, S<:IndexSpace, N₁, N₂} endAbstract supertype of all tensor maps, i.e. linear maps between tensor products of vector spaces of type S<:IndexSpace, with element type T. An AbstractTensorMap maps from an input space of type ProductSpace{S, N₂} to an output space of type ProductSpace{S, N₁}.
The following concrete subtypes are provided within the TensorKit library:
TensorKit.TensorMap — Typestruct TensorMap{T, S<:IndexSpace, N₁, N₂, A<:DenseVector{T}} <: AbstractTensorMap{T, S, N₁, N₂}Specific subtype of AbstractTensorMap for representing tensor maps (morphisms in a tensor category), where the data is stored in a dense vector.
TensorKit.DiagonalTensorMap — TypeDiagonalTensorMap{T}(undef, domain::S) where {T,S<:IndexSpace}
# expert mode: select storage type `A`
DiagonalTensorMap{T,S,A}(undef, domain::S) where {T,S<:IndexSpace,A<:DenseVector{T}}Construct a DiagonalTensorMap with uninitialized data.
TensorKit.AdjointTensorMap — Typestruct AdjointTensorMap{T, S, N₁, N₂, TT<:AbstractTensorMap} <: AbstractTensorMap{T, S, N₁, N₂}Specific subtype of AbstractTensorMap that is a lazy wrapper for representing the adjoint of an instance of AbstractTensorMap.
TensorKit.BraidingTensor — Typestruct BraidingTensor{T,S<:IndexSpace} <: AbstractTensorMap{T, S, 2, 2}
BraidingTensor(V1::S, V2::S, adjoint::Bool=false) where {S<:IndexSpace}Specific subtype of AbstractTensorMap for representing the braiding tensor that braids the first input over the second input; its inverse can be obtained as the adjoint.
It holds that domain(BraidingTensor(V1, V2)) == V1 ⊗ V2 and codomain(BraidingTensor(V1, V2)) == V2 ⊗ V1.
Of those, TensorMap provides the generic instantiation of our tensor concept. It supports various constructors, which are discussed in the next subsection.
Furthermore, some aliases are provided for convenience:
TensorKit.AbstractTensor — TypeAbstractTensor{T,S,N} = AbstractTensorMap{T,S,N,0}Abstract supertype of all tensors, i.e. elements in the tensor product space of type ProductSpace{S, N}, with element type T.
An AbstractTensor{T, S, N} is actually a special case AbstractTensorMap{T, S, N, 0}, i.e. a tensor map with only non-trivial output spaces.
TensorKit.Tensor — TypeTensor{T, S, N, A<:DenseVector{T}} = TensorMap{T, S, N, 0, A}Specific subtype of AbstractTensor for representing tensors whose data is stored in a dense vector.
A Tensor{T, S, N, A} is actually a special case TensorMap{T, S, N, 0, A}, i.e. a tensor map with only a non-trivial output space.
TensorMap constructors
General constructors
A TensorMap with undefined data can be constructed by specifying its domain and codomain:
TensorKit.TensorMap — MethodTensorMap{T}(undef, codomain::ProductSpace{S,N₁}, domain::ProductSpace{S,N₂})
where {T,S,N₁,N₂}
TensorMap{T}(undef, codomain ← domain)
TensorMap{T}(undef, domain → codomain)
# expert mode: select storage type `A`
TensorMap{T,S,N₁,N₂,A}(undef, codomain ← domain)
TensorMap{T,S,N₁,N₂,A}(undef, domain → domain)Construct a TensorMap with uninitialized data.
The resulting object can then be filled with data using the setindex! method as discussed below, using functions such as VectorInterface.zerovector!, rand! or fill!, or it can be used as an output argument in one of the many methods that accept output arguments, or in an @tensor output[...] = ... expression.
Alternatively, a TensorMap can be constructed by specifying its data, codmain and domain in one of the following ways:
TensorKit.TensorMap — MethodTensorMap(data::AbstractDict{<:Sector,<:AbstractMatrix}, codomain::ProductSpace{S,N₁},
domain::ProductSpace{S,N₂}) where {S<:ElementarySpace,N₁,N₂}
TensorMap(data, codomain ← domain)
TensorMap(data, domain → codomain)Construct a TensorMap by explicitly specifying its block data.
Arguments
data::AbstractDict{<:Sector,<:AbstractMatrix}: dictionary containing the block data for each coupled sectorcas a matrix of size(blockdim(codomain, c), blockdim(domain, c)).codomain::ProductSpace{S,N₁}: the codomain as aProductSpaceofN₁spaces of typeS<:ElementarySpace.domain::ProductSpace{S,N₂}: the domain as aProductSpaceofN₂spaces of typeS<:ElementarySpace.
Alternatively, the domain and codomain can be specified by passing a HomSpace using the syntax codomain ← domain or domain → codomain.
TensorKit.TensorMap — MethodTensorMap(data::AbstractArray, codomain::ProductSpace{S,N₁}, domain::ProductSpace{S,N₂};
tol=sqrt(eps(real(float(eltype(data)))))) where {S<:ElementarySpace,N₁,N₂}
TensorMap(data, codomain ← domain; tol=sqrt(eps(real(float(eltype(data))))))
TensorMap(data, domain → codomain; tol=sqrt(eps(real(float(eltype(data))))))Construct a TensorMap from a plain multidimensional array.
Arguments
data::DenseArray: tensor data as a plain array.codomain::ProductSpace{S,N₁}: the codomain as aProductSpaceofN₁spaces of typeS<:ElementarySpace.domain::ProductSpace{S,N₂}: the domain as aProductSpaceofN₂spaces of typeS<:ElementarySpace.tol=sqrt(eps(real(float(eltype(data)))))::Float64:
Here, data can be specified in three ways:
datacan be aDenseVectorof lengthdim(codomain ← domain); in that case it represents the actual independent entries of the tensor map. An instance will be created that directly referencesdata.datacan be anAbstractMatrixof size(dim(codomain), dim(domain))datacan be anAbstractArrayof rankN₁ + N₂with a size matching that of the domain and codomain spaces, i.e.size(data) == (dims(codomain)..., dims(domain)...)
In case 2 and 3, the TensorMap constructor will reconstruct the tensor data such that the resulting tensor t satisfies data == convert(Array, t), up to an error specified by tol. For the case where sectortype(S) == Trivial and data isa DenseArray, the data array is simply reshaped into a vector and used as in case 1 so that the memory will still be shared. In other cases, new memory will be allocated.
Note that in the case of N₁ + N₂ = 1, case 3 also amounts to data being a vector, whereas when N₁ + N₂ == 2, case 2 and case 3 both require data to be a matrix. Such ambiguous cases are resolved by checking the size of data in an attempt to support all possible cases.
Finally, we also support the following Array-like constructors
Base.zeros — Methodzeros([T=Float64,], codomain::ProductSpace{S,N₁}, domain::ProductSpace{S,N₂}) where {S,N₁,N₂,T}
zeros([T=Float64,], codomain ← domain)Create a TensorMap with element type T, of all zeros with spaces specified by codomain and domain.
Base.ones — Methodones([T=Float64,], codomain::ProductSpace{S,N₁}, domain::ProductSpace{S,N₂}) where {S,N₁,N₂,T}
ones([T=Float64,], codomain ← domain)Create a TensorMap with element type T, of all ones with spaces specified by codomain and domain.
Base.rand — Methodrand([rng=default_rng()], [T=Float64], codomain::ProductSpace{S,N₁},
domain::ProductSpace{S,N₂}) where {S,N₁,N₂,T} -> t
rand([rng=default_rng()], [T=Float64], codomain ← domain) -> tGenerate a tensor t with entries generated by rand.
See also Random.rand!.
Base.randn — Methodrandn([rng=default_rng()], [T=Float64], codomain::ProductSpace{S,N₁},
domain::ProductSpace{S,N₂}) where {S,N₁,N₂,T} -> t
randn([rng=default_rng()], [T=Float64], codomain ← domain) -> tGenerate a tensor t with entries generated by randn.
See also Random.randn!.
Random.randexp — Methodrandexp([rng=default_rng()], [T=Float64], codomain::ProductSpace{S,N₁},
domain::ProductSpace{S,N₂}) where {S,N₁,N₂,T} -> t
randexp([rng=default_rng()], [T=Float64], codomain ← domain) -> tGenerate a tensor t with entries generated by randexp.
See also Random.randexp!.
as well as a similar constructor
Base.similar — Methodsimilar(t::AbstractTensorMap, [AorT=storagetype(t)], [V=space(t)])
similar(t::AbstractTensorMap, [AorT=storagetype(t)], codomain, domain)Creates an uninitialized mutable tensor with the given scalar or storagetype AorT and structure V or codomain ← domain, based on the source tensormap. The second and third arguments are both optional, defaulting to the given tensor's storagetype and space. The structure may be specified either as a single HomSpace argument or as codomain and domain.
By default, this will result in TensorMap{T}(undef, V) when custom objects do not specialize this method.
Specific constructors
Additionally, the following methods can be used to construct specific TensorMap instances.
TensorKit.id — Functionid([T::Type=Float64,] V::TensorSpace) -> TensorMap
id!(t::AbstractTensorMap) -> AbstractTensorMapConstruct the identity endomorphism on space V, i.e. return a t::TensorMap with domain(t) == codomain(t) == V, where either scalartype(t) = T if T is a Number type or storagetype(t) = T if T is a DenseVector type.
See also one!.
TensorKit.isomorphism — Functionisomorphism([T::Type=Float64,] codomain::TensorSpace, domain::TensorSpace) -> TensorMap
isomorphism([T::Type=Float64,] codomain ← domain) -> TensorMap
isomorphism([T::Type=Float64,] domain → codomain) -> TensorMap
isomorphism!(t::AbstractTensorMap) -> AbstractTensorMapConstruct a specific isomorphism between the codomain and the domain, i.e. return a t::TensorMap where either scalartype(t) = T if T is a Number type or storagetype(t) = T if T is a DenseVector type. If the spaces are not isomorphic, an error will be thrown.
There is no canonical choice for a specific isomorphism, but the current choice is such that isomorphism(cod, dom) == inv(isomorphism(dom, cod)).
See also unitary when InnerProductStyle(cod) === EuclideanInnerProduct().
TensorKit.unitary — Functionunitary([T::Type=Float64,] codomain::TensorSpace, domain::TensorSpace) -> TensorMap
unitary([T::Type=Float64,] codomain ← domain) -> TensorMap
unitary([T::Type=Float64,] domain → codomain) -> TensorMap
unitary!(t::AbstractTensorMap) -> AbstractTensorMapConstruct a specific unitary morphism between the codomain and the domain, i.e. return a t::TensorMap where either scalartype(t) = T if T is a Number type or storagetype(t) = T if T is a DenseVector type. If the spaces are not isomorphic, or the spacetype does not have a Euclidean inner product, an error will be thrown.
There is no canonical choice for a specific unitary, but the current choice is such that unitary(cod, dom) == inv(unitary(dom, cod)) = adjoint(unitary(dom, cod)).
See also isomorphism and isometry.
TensorKit.isometry — Functionisometry([T::Type=Float64,] codomain::TensorSpace, domain::TensorSpace) -> TensorMap
isometry([T::Type=Float64,] codomain ← domain) -> TensorMap
isometry([T::Type=Float64,] domain → codomain) -> TensorMap
isometry!(t::AbstractTensorMap) -> AbstractTensorMapConstruct a specific isometry between the codomain and the domain, i.e. return a t::TensorMap where either scalartype(t) = T if T is a Number type or storagetype(t) = T if T is a DenseVector type. The isometry t then satisfies t' * t = id(domain) and (t * t')^2 = t * t'. If the spaces do not allow for such an isometric inclusion, an error will be thrown.
See also isomorphism and unitary.
AbstractTensorMap properties and data access
The following methods exist to obtain type information:
Base.eltype — Methodeltype(::AbstractTensorMap) -> Type{T}
eltype(::Type{<:AbstractTensorMap}) -> Type{T}Return the scalar or element type T of a tensor.
TensorKit.spacetype — Methodspacetype(a) -> Type{S<:IndexSpace}
spacetype(::Type) -> Type{S<:IndexSpace}Return the type of the elementary space S of object a (e.g. a tensor). Also works in type domain.
TensorKit.sectortype — Methodsectortype(a) -> Type{<:Sector}
sectortype(::Type) -> Type{<:Sector}Return the type of sector over which object a (e.g. a representation space or a tensor) is defined. Also works in type domain.
TensorKit.field — Methodfield(a) -> Type{𝔽<:Field}
field(::Type{T}) -> Type{𝔽<:Field}Return the type of field over which object a (e.g. a vector space or a tensor) is defined. This also works in type domain.
TensorKit.storagetype — Functionstoragetype(t::AbstractTensorMap) -> Type{A<:AbstractVector}
storagetype(T::Type{<:AbstractTensorMap}) -> Type{A<:AbstractVector}Return the type of vector that stores the data of a tensor.
TensorKit.blocktype — Functionblocktype(t)Return the type of the matrix blocks of a tensor.
To obtain information about the indices, you can use:
TensorKit.space — Methodspace(t::AbstractTensorMap{T,S,N₁,N₂}) -> HomSpace{S,N₁,N₂}
space(t::AbstractTensorMap{T,S,N₁,N₂}, i::Int) -> SThe index information of a tensor, i.e. the HomSpace of its domain and codomain. If i is specified, return the i-th index space.
TensorKit.domain — Functiondomain(t::AbstractTensorMap{T,S,N₁,N₂}) -> ProductSpace{S,N₂}
domain(t::AbstractTensorMap{T,S,N₁,N₂}, i::Int) -> SReturn the domain of a tensor, i.e. the product space of the input spaces. If i is specified, return the i-th input space. Implementations should provide domain(t).
TensorKit.codomain — Functioncodomain(t::AbstractTensorMap{T,S,N₁,N₂}) -> ProductSpace{S,N₁}
codomain(t::AbstractTensorMap{T,S,N₁,N₂}, i::Int) -> SReturn the codomain of a tensor, i.e. the product space of the output spaces. If i is specified, return the i-th output space. Implementations should provide codomain(t).
TensorKit.numin — Functionnumin(::Union{TT,Type{TT}}) where {TT<:AbstractTensorMap} -> IntReturn the number of input spaces of a tensor. This is equivalent to the number of spaces in the domain of that tensor.
TensorKit.numout — Functionnumout(::Union{TT,Type{TT}}) where {TT<:AbstractTensorMap} -> IntReturn the number of output spaces of a tensor. This is equivalent to the number of spaces in the codomain of that tensor.
TensorKit.numind — Functionnumind(::Union{T,Type{T}}) where {T<:AbstractTensorMap} -> IntReturn the total number of input and output spaces of a tensor. This is equivalent to the total number of spaces in the domain and codomain of that tensor.
TensorKit.codomainind — Functioncodomainind(::Union{TT,Type{TT}}) where {TT<:AbstractTensorMap} -> Tuple{Int}Return all indices of the codomain of a tensor.
TensorKit.domainind — Functiondomainind(::Union{TT,Type{TT}}) where {TT<:AbstractTensorMap} -> Tuple{Int}Return all indices of the domain of a tensor.
See also codomainind and allind.
TensorKit.allind — Functionallind(::Union{TT,Type{TT}}) where {TT<:AbstractTensorMap} -> Tuple{Int}Return all indices of a tensor, i.e. the indices of its domain and codomain.
See also codomainind and domainind.
In TensorMap instances, all data is gathered in a single AbstractVector, which has an internal structure into blocks associated to total coupled charge, within which live subblocks associated with the different possible fusion-splitting tree pairs.
To obtain information about the structure of the data, you can use:
TensorKit.fusionblockstructure — Methodfusionblockstructure(t::AbstractTensorMap) -> TensorStructureReturn the necessary structure information to decompose a tensor in blocks labeled by coupled sectors and in subblocks labeled by a splitting-fusion tree couple.
TensorKitSectors.dim — Methoddim(t::AbstractTensorMap) -> IntThe total number of free parameters of a tensor, discounting the entries that are fixed by symmetry. This is also the dimension of the HomSpace on which the TensorMap is defined.
TensorKit.blocksectors — Methodblocksectors(t::AbstractTensorMap)Return an iterator over all coupled sectors of a tensor.
TensorKit.hasblock — Methodhasblock(t::AbstractTensorMap, c::Sector) -> BoolVerify whether a tensor has a block corresponding to a coupled sector c.
TensorKit.fusiontrees — Methodfusiontrees(t::AbstractTensorMap)Return an iterator over all splitting - fusion tree pairs of a tensor.
Data can be accessed (and modified) in a number of ways. To access the full matrix block associated with the coupled charges, you can use:
TensorKit.block — Functionblock(t::AbstractTensorMap, c::Sector)Return the matrix block of a tensor corresponding to a coupled sector c.
See also blocks, blocksectors, blockdim and hasblock.
TensorKit.blocks — Functionblocks(t::AbstractTensorMap)Return an iterator over all blocks of a tensor, i.e. all coupled sectors and their corresponding matrix blocks.
See also block, blocksectors, blockdim and hasblock.
To access the data associated with a specific fusion tree pair, you can use:
Base.getindex — MethodBase.getindex(t::TensorMap{T,S,N₁,N₂,I},
f₁::FusionTree{I,N₁},
f₂::FusionTree{I,N₂}) where {T,SN₁,N₂,I<:Sector}
-> StridedViews.StridedView
t[f₁, f₂]Return a view into the data slice of t corresponding to the splitting - fusion tree pair (f₁, f₂). In particular, if f₁.coupled == f₂.coupled == c, then a StridedViews.StridedView of size (dims(codomain(t), f₁.uncoupled)..., dims(domain(t), f₂.uncoupled)) is returned which represents the slice of block(t, c) whose row indices correspond to f₁.uncoupled and column indices correspond to f₂.uncoupled.
Base.setindex! — MethodBase.setindex!(t::TensorMap{T,S,N₁,N₂,I},
v,
f₁::FusionTree{I,N₁},
f₂::FusionTree{I,N₂}) where {T,S,N₁,N₂,I<:Sector}
t[f₁, f₂] = vCopies v into the data slice of t corresponding to the splitting - fusion tree pair (f₁, f₂). Here, v can be any object that can be copied into a StridedViews.StridedView of size (dims(codomain(t), f₁.uncoupled)..., dims(domain(t), f₂.uncoupled)) using Base.copy!.
For a tensor t with FusionType(sectortype(t)) isa UniqueFusion, fusion trees are completely determined by the outcoming sectors, and the data can be accessed in a more straightforward way:
Base.getindex — MethodBase.getindex(t::TensorMap
sectors::NTuple{N₁+N₂,I}) where {N₁,N₂,I<:Sector}
-> StridedViews.StridedView
t[sectors]Return a view into the data slice of t corresponding to the splitting - fusion tree pair with combined uncoupled charges sectors. In particular, if sectors == (s₁..., s₂...) where s₁ and s₂ correspond to the uncoupled charges in the codomain and domain respectively, then a StridedViews.StridedView of size (dims(codomain(t), s₁)..., dims(domain(t), s₂)) is returned.
This method is only available for the case where FusionStyle(I) isa UniqueFusion, since it assumes a uniquely defined coupled charge.
For tensor t with sectortype(t) == Trivial, the data can be accessed and manipulated directly as multidimensional arrays:
Base.getindex — MethodBase.getindex(t::AbstractTensorMap)
t[]Return a view into the data of t as a StridedViews.StridedView of size (dims(codomain(t))..., dims(domain(t))...).
Base.getindex — MethodBase.getindex(t::AbstractTensorMap, indices::Vararg{Int})
t[indices]Return a view into the data slice of t corresponding to indices, by slicing the StridedViews.StridedView into the full data array.
Base.setindex! — MethodBase.setindex!(t::AbstractTensorMap, v, indices::Vararg{Int})
t[indices] = vAssigns v to the data slice of t corresponding to indices.
The tensor data can also be filled with random numbers via
Random.rand! — Functionrand!([rng=default_rng()], t::AbstractTensorMap) -> tFill the tensor t with entries generated by rand!.
See also Random.rand.
Random.randn! — Functionrandn!([rng=default_rng()], t::AbstractTensorMap) -> tFill the tensor t with entries generated by randn!.
See also Random.randn.
Random.randexp! — Functionrandexp!([rng=default_rng()], t::AbstractTensorMap) -> tFill the tensor t with entries generated by randexp!.
See also Random.randexp.
AbstractTensorMap operations
The operations that can be performed on an AbstractTensorMap can be organized into the following categories:
vector operations: these do not change the
spaceor index strucure of a tensor and can be straightforwardly implemented on on the full data. All the methods described in VectorInterface.jl are supported. For compatibility reasons, we also provide implementations for equivalent methods from LinearAlgebra.jl, such asaxpy!,axpby!.index manipulations: these change (permute) the index structure of a tensor, which affects the data in a way that is fully determined by the categorical data of the
sectortypeof the tensor.(planar) contractions and (planar) traces (i.e., contractions with identity tensors). Tensor contractions correspond to a combination of some index manipulations followed by a composition or multiplication of the tensors in their role as linear maps. Tensor contractions are however of such important and frequency that they require a dedicated implementation.
tensor factorisations, which relies on their identification of tensors with linear maps between tensor spaces. The factorisations are applied as ordinary matrix factorisations to the matrix blocks associated with the coupled charges.
Index manipulations
A general index manipulation of a TensorMap object can be built up by considering some transformation of the fusion trees, along with a permutation of the stored data. They come in three flavours, which are either of the type transform(!) which are exported, or of the type add_transform!, for additional expert-mode options that allows for addition and scaling, as well as the selection of a custom backend.
TensorKit.permute — Methodpermute(tsrc::AbstractTensorMap, (p₁, p₂)::Index2Tuple;
copy::Bool=false)
-> tdst::TensorMapReturn tensor tdst obtained by permuting the indices of tsrc. The codomain and domain of tdst correspond to the indices in p₁ and p₂ of tsrc respectively.
If copy=false, tdst might share data with tsrc whenever possible. Otherwise, a copy is always made.
To permute into an existing destination, see permute! and add_permute!
TensorKit.braid — Methodbraid(tsrc::AbstractTensorMap, (p₁, p₂)::Index2Tuple, levels::IndexTuple;
copy::Bool = false)
-> tdst::TensorMapReturn tensor tdst obtained by braiding the indices of tsrc. The codomain and domain of tdst correspond to the indices in p₁ and p₂ of tsrc respectively. Here, levels is a tuple of length numind(tsrc) that assigns a level or height to the indices of tsrc, which determines whether they will braid over or under any other index with which they have to change places.
If copy=false, tdst might share data with tsrc whenever possible. Otherwise, a copy is always made.
To braid into an existing destination, see braid! and add_braid!
Base.transpose — Methodtranspose(tsrc::AbstractTensorMap, (p₁, p₂)::Index2Tuple;
copy::Bool=false)
-> tdst::TensorMapReturn tensor tdst obtained by transposing the indices of tsrc. The codomain and domain of tdst correspond to the indices in p₁ and p₂ of tsrc respectively. The new index positions should be attainable without any indices crossing each other, i.e., the permutation (p₁..., reverse(p₂)...) should constitute a cyclic permutation of (codomainind(tsrc)..., reverse(domainind(tsrc))...).
If copy=false, tdst might share data with tsrc whenever possible. Otherwise, a copy is always made.
To permute into an existing destination, see permute! and add_permute!
TensorKit.repartition — Methodrepartition(tsrc::AbstractTensorMap{S}, N₁::Int, N₂::Int; copy::Bool=false) where {S}
-> tdst::AbstractTensorMap{S,N₁,N₂}Return tensor tdst obtained by repartitioning the indices of t. The codomain and domain of tdst correspond to the first N₁ and last N₂ spaces of t, respectively.
If copy=false, tdst might share data with tsrc whenever possible. Otherwise, a copy is always made.
To repartition into an existing destination, see repartition!.
TensorKit.flip — Methodflip(t::AbstractTensorMap, I) -> t′::AbstractTensorMapReturn a new tensor that is isomorphic to t but where the arrows on the indices i that satisfy i ∈ I are flipped, i.e. space(t′, i) = flip(space(t, i)).
The isomorphism that flip applies to each of the indices i ∈ I is such that flipping two indices that are afterwards contracted within an @tensor contraction will yield the same result as without flipping those indices first. However, flip is not involutory, i.e. flip(flip(t, I), I) != t in general. To obtain the original tensor, one can use the inv keyword, i.e. it holds that flip(flip(t, I), I; inv=true) == t.
TensorKitSectors.twist — Methodtwist(tsrc::AbstractTensorMap, i::Int; inv::Bool=false) -> tdst
twist(tsrc::AbstractTensorMap, is; inv::Bool=false) -> tdstApply a twist to the ith index of tsrc and return the result as a new tensor. If inv=true, use the inverse twist.
See twist! for storing the result in place.
TensorKit.insertleftunit — Methodinsertleftunit(tsrc::AbstractTensorMap, i=numind(t) + 1;
conj=false, dual=false, copy=false) -> tdstInsert a trivial vector space, isomorphic to the underlying field, at position i, which can be specified as an Int or as Val(i) for improved type stability. More specifically, adds a left monoidal unit or its dual.
If copy=false, tdst might share data with tsrc whenever possible. Otherwise, a copy is always made.
See also insertrightunit, removeunit.
TensorKit.insertrightunit — Methodinsertrightunit(tsrc::AbstractTensorMap, i=numind(t);
conj=false, dual=false, copy=false) -> tdstInsert a trivial vector space, isomorphic to the underlying field, after position i, which can be specified as an Int or as Val(i) for improved type stability. More specifically, adds a right monoidal unit or its dual.
If copy=false, tdst might share data with tsrc whenever possible. Otherwise, a copy is always made.
See also insertleftunit, removeunit.
TensorKit.removeunit — Methodremoveunit(tsrc::AbstractTensorMap, i; copy=false) -> tdstThis removes a trivial tensor product factor at position 1 ≤ i ≤ N, where i can be specified as an Int or as Val(i) for improved type stability. For this to work, that factor has to be isomorphic to the field of scalars.
If copy=false, tdst might share data with tsrc whenever possible. Otherwise, a copy is always made.
This operation undoes the work of insertleftunit and insertrightunit.
Base.permute! — Methodpermute!(tdst::AbstractTensorMap, tsrc::AbstractTensorMap, (p₁, p₂)::Index2Tuple)
-> tdstWrite into tdst the result of permuting the indices of tsrc. The codomain and domain of tdst correspond to the indices in p₁ and p₂ of tsrc respectively.
See permute for creating a new tensor and add_permute! for a more general version.
TensorKit.braid! — Functionbraid!(tdst::AbstractTensorMap, tsrc::AbstractTensorMap,
(p₁, p₂)::Index2Tuple, levels::Tuple)
-> tdstWrite into tdst the result of braiding the indices of tsrc. The codomain and domain of tdst correspond to the indices in p₁ and p₂ of tsrc respectively. Here, levels is a tuple of length numind(tsrc) that assigns a level or height to the indices of tsrc, which determines whether they will braid over or under any other index with which they have to change places.
See braid for creating a new tensor and add_braid! for a more general version.
LinearAlgebra.transpose! — Functiontranspose!(tdst::AbstractTensorMap, tsrc::AbstractTensorMap,
(p₁, p₂)::Index2Tuple)
-> tdstWrite into tdst the result of transposing the indices of tsrc. The codomain and domain of tdst correspond to the indices in p₁ and p₂ of tsrc respectively. The new index positions should be attainable without any indices crossing each other, i.e., the permutation (p₁..., reverse(p₂)...) should constitute a cyclic permutation of (codomainind(tsrc)..., reverse(domainind(tsrc))...).
See transpose for creating a new tensor and add_transpose! for a more general version.
TensorKit.repartition! — Functionrepartition!(tdst::AbstractTensorMap{S}, tsrc::AbstractTensorMap{S}) where {S} -> tdstWrite into tdst the result of repartitioning the indices of tsrc. This is just a special case of a transposition that only changes the number of in- and outgoing indices.
See repartition for creating a new tensor.
TensorKit.twist! — Functiontwist!(t::AbstractTensorMap, i::Int; inv::Bool=false) -> t
twist!(t::AbstractTensorMap, is; inv::Bool=false) -> tApply a twist to the ith index of t, or all indices in is, storing the result in t. If inv=true, use the inverse twist.
See twist for creating a new tensor.
TensorKit.add_permute! — Functionadd_permute!(tdst::AbstractTensorMap, tsrc::AbstractTensorMap, (p₁, p₂)::Index2Tuple,
α::Number, β::Number, backend::AbstractBackend...)Return the updated tdst, which is the result of adding α * tsrc to tdst after permuting the indices of tsrc according to (p₁, p₂).
See also permute, permute!, add_braid!, add_transpose!.
TensorKit.add_braid! — Functionadd_braid!(tdst::AbstractTensorMap, tsrc::AbstractTensorMap, (p₁, p₂)::Index2Tuple,
levels::IndexTuple, α::Number, β::Number, backend::AbstractBackend...)Return the updated tdst, which is the result of adding α * tsrc to tdst after braiding the indices of tsrc according to (p₁, p₂) and levels.
See also braid, braid!, add_permute!, add_transpose!.
TensorKit.add_transpose! — Functionadd_transpose!(tdst::AbstractTensorMap, tsrc::AbstractTensorMap, (p₁, p₂)::Index2Tuple,
α::Number, β::Number, backend::AbstractBackend...)Return the updated tdst, which is the result of adding α * tsrc to tdst after transposing the indices of tsrc according to (p₁, p₂).
See also transpose, transpose!, add_permute!, add_braid!.
Tensor map composition, traces, contractions and tensor products
TensorKit.compose — Methodcompose(t1::AbstractTensorMap, t2::AbstractTensorMap) -> AbstractTensorMapReturn the AbstractTensorMap that implements the composition of the two tensor maps t1 and t2.
TensorKit.trace_permute! — Functiontrace_permute!(tdst::AbstractTensorMap, tsrc::AbstractTensorMap,
(p₁, p₂)::Index2Tuple, (q₁, q₂)::Index2Tuple,
α::Number, β::Number, backend=TO.DefaultBackend())Return the updated tdst, which is the result of adding α * tsrc to tdst after permuting the indices of tsrc according to (p₁, p₂) and furthermore tracing the indices in q₁ and q₂.
TensorKit.contract! — Functioncontract!(C::AbstractTensorMap,
A::AbstractTensorMap, (oindA, cindA)::Index2Tuple,
B::AbstractTensorMap, (cindB, oindB)::Index2Tuple,
(p₁, p₂)::Index2Tuple,
α::Number, β::Number,
backend, allocator)Return the updated C, which is the result of adding α * A * B to C after permuting the indices of A and B according to (oindA, cindA) and (cindB, oindB) respectively.
TensorKitSectors.:⊗ — Method⊗(t1::AbstractTensorMap, t2::AbstractTensorMap, ...) -> TensorMap
otimes(t1::AbstractTensorMap, t2::AbstractTensorMap, ...) -> TensorMapCompute the tensor product between two AbstractTensorMap instances, which results in a new TensorMap instance whose codomain is codomain(t1) ⊗ codomain(t2) and whose domain is domain(t1) ⊗ domain(t2).
TensorMap factorizations
The factorisation methods are powered by MatrixAlgebraKit.jl and all follow the same strategy. The idea is that the TensorMap is interpreted as a linear map based on the current partition of indices between domain and codomain, and then the entire range of MatrixAlgebraKit functions can be called. Factorizing a tensor according to a different partition of the indices is possible by prepending the factorization step with an explicit call to permute or transpose.
For the full list of factorizations, see Decompositions.
Additionally, it is possible to obtain truncated versions of some of these factorizations through the MatrixAlgebraKit.TruncationStrategy objects.
The exact truncation strategy can be controlled through the strategies defined in Truncations, but for TensorMaps there is also the special-purpose scheme:
TensorKit.Factorizations.truncspace — Functiontruncspace(space::ElementarySpace; by=abs, rev::Bool=true)Truncation strategy to keep the first values for each sector when sorted according to by and rev, such that the resulting vector space is no greater than V.