Tensors
LinearCombinations.AbstractTensor — Type
AbstractTensor{T<:Tuple}The supertype of all tensor types. The most important subtype is Tensor. There are also twisted tensors.
Constructors
LinearCombinations.Tensor — Type
Tensor{T<:Tuple}
Tensor{T}(xs...) where T
Tensor(xs...)The type Tensor represents pure tensors.
A general tensor is a linear combination of pure tensors and can conveniently be created using tensor. LinearCombinations takes pure tensors as basis elements.
A Tensor can be created out of a Tuple or out of the individual components. The second form is not available if the tensor has a tuple as its only component.
Tensor implements the iteration and indexing interfaces. This makes for example splatting available for tensors, and the i-th component of t::Tensor can be accessed as t[i].
Tensors can be nested. Different bracketings lead to different tensors. The functions cat, flatten, swap and the type Regroup are provided to make rearranging tensors more easily.
Note that the type parameter of Tensor is always a Tuple. For instance, the type of a Tensor with two components of types T1 and T2 is Tensor{Tuple{T1,T2}}, not Tensor{T1,T2}.
See also tensor, cat, flatten, swap, Regroup.
Examples
julia> t = Tensor('x', 'y', "z")
'x'⊗'y'⊗"z"
julia> typeof(t)
Tensor{Tuple{Char, Char, String}}
julia> Tuple(t)
('x', 'y', "z")
julia> length(t), t[2], t[end]
(3, 'y', "z")
julia> a = Linear('x' => 1, 'y' => 2)
Linear{Char, Int64} with 2 terms:
'x'+2*'y'
julia> b = Linear(Tensor('x', 'z') => 1, Tensor('y', 'z') => 2)
Linear{Tensor{Tuple{Char, Char}}, Int64} with 2 terms:
'x'⊗'z'+2*'y'⊗'z'
julia> b == tensor(a, 'z')
true
julia> [uppercase(x) for x in t]
3-element Vector{Any}:
'X': ASCII/Unicode U+0058 (category Lu: Letter, uppercase)
'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
"Z"
julia> f((x1, xs...)::Tensor) = x1
f (generic function with 1 method)
julia> f(t)
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)
julia> t == Tensor(Tensor('x', 'y'), "z")
false
julia> Tensor() |> typeof
Tensor{Tuple{}}LinearCombinations.tensor — Function
x ⊗ y -> AbstractLinear{<:Tensor}
⊗(xs...) -> AbstractLinear{<:Tensor}
tensor(xs...) -> AbstractLinear{<:Tensor}tensor is the multilinear extension of Tensor. The ⊗ operator is a synomym for tensor. The return value is a Tensor if no argument is of type AbstractLinear. It is DenseLinear if all arguments are DenseLinear; the corresponding basis is the TensorBasis of the bases of the arguments. In all other cases the return type is Linear. This can be overriden via the addto keyword argument.
Remember that ⊗ is not associative in Julia, unlike *. Writing tensors with more than two factors in infix notation therefore produces nested tensors.
See also Tensor, @multilinear, TensorBasis.
Examples
julia> tensor('x', "w")
'x'⊗"w"
julia> a = Linear('x' => 1, 'y' => 2)
Linear{Char, Int64} with 2 terms:
'x'+2*'y'
julia> b = Linear("w" => 3, "z" => -1)
Linear{String, Int64} with 2 terms:
3*"w"-"z"
julia> tensor(a, "w")
Linear{Tensor{Tuple{Char, String}}, Int64} with 2 terms:
'x'⊗"w"+2*'y'⊗"w"
julia> a ⊗ b
Linear{Tensor{Tuple{Char, String}}, Int64} with 4 terms:
-2*'y'⊗"z"+3*'x'⊗"w"+6*'y'⊗"w"-'x'⊗"z"
julia> tensor('x', b, a; coefftype = Float64)
Linear{Tensor{Tuple{Char, String, Char}}, Float64} with 4 terms:
3.0*'x'⊗"w"⊗'x'-'x'⊗"z"⊗'x'+6.0*'x'⊗"w"⊗'y'-2.0*'x'⊗"z"⊗'y'
julia> 'x' ⊗ b ⊗ a
Linear{Tensor{Tuple{Tensor{Tuple{Char, String}}, Char}}, Int64} with 4 terms:
-2*('x'⊗"z")⊗'y'-('x'⊗"z")⊗'x'+3*('x'⊗"w")⊗'x'+6*('x'⊗"w")⊗'y'
julia> tensor('x', b, a) == 'x' ⊗ b ⊗ a
false
julia> tensor() |> typeof
Tensor{Tuple{}}
julia> d = DenseLinear(a; basis = Basis('w':'z'))
DenseLinear{Char, Int64} with 2 terms:
'x'+2*'y'
julia> d ⊗ d
DenseLinear{Tensor{Tuple{Char, Char}}, Int64} with 4 terms:
'x'⊗'x'+2*'y'⊗'x'+2*'x'⊗'y'+4*'y'⊗'y'
julia> d ⊗ d == a ⊗ a
true
julia> basis(d ⊗ d)
TensorBasis(Basis('w':1:'z'), Basis('w':1:'z'))Manipulating tensors
Base.fieldtypes — Function
fieldtypes(::Type{T}) where T <:AbstractTensor -> TupleReturn the types of the components of T as a tuple.
Example
julia> fieldtypes(Tensor{Tuple{Char, String}})
(Char, String)Core.Tuple — Method
Tuple(t::AbstractTensor{T}) -> T <: TupleReturn the tuple of components of t.
Although any AbstractTensor has to supports the iteration interface, it is often more efficient to deal with the underlying Tuple of components. For instance, functions like map or reduce map return a Tuple in this case instead of a Vector.
Example
julia> t = Tensor('A','b','c')
'A'⊗'b'⊗'c'
julia> Tuple(t)
('A', 'b', 'c')
julia> map(isuppercase, t)
3-element Vector{Bool}:
1
0
0
julia> map(isuppercase, Tuple(t))
(true, false, false)LinearCombinations.cat — Function
LinearCombinations.cat(t::AbstractTensor...) -> TensorConcatenate the tensors given as arguments. This function is multilinear.
See also flatten.
Example
julia> LinearCombinations.cat(Tensor('x'), Tensor('y', Tensor('z', 'w')))
'x'⊗'y'⊗('z'⊗'w')LinearCombinations.flatten — Function
flatten(t::AbstractTensor) -> Tensor
flatten(a::AbstractLinear{<:AbstractTensor}) -> AbstractLinear{Tensor}Recursively take all tensor components and concatenate the result. This function is linear.
See also cat.
Example
julia> t = Tensor('x', Tensor('y', Tensor('z', 'w')))
'x'⊗('y'⊗('z'⊗'w'))
julia> flatten(t)
'x'⊗'y'⊗'z'⊗'w'LinearCombinations.swap — Constant
swap(t::AbstractTensor{Tuple{T1,T2}}) where {T1,T2}This linear function swaps the components of two-component tensors. If the two components of a tensor t have non-zero degrees, then the usual sign (-1)^(deg(t[1])*deg(t[2])) is introduced. In this case the returned value is of type Linear1 instead of Tensor. By default, all terms have zero degree.
Note that swap is a special case of regroup: it is simply defined as regroup(:((1, 2)), :((2, 1))).
See also Tensor, deg, regroup, LinearCombinations.DefaultCoefftype.
Examples
Examples without degrees
julia> t = Tensor("x", "z")
"x"⊗"z"
julia> swap(t)
"z"⊗"x"
julia> a = Linear("x" => 1, "yy" => 1) ⊗ Linear("z" => 1, "ww" => 1)
Linear{Tensor{Tuple{String, String}}, Int64} with 4 terms:
"x"⊗"z"+"x"⊗"ww"+"yy"⊗"z"+"yy"⊗"ww"
julia> swap(a)
Linear{Tensor{Tuple{String, String}}, Int64} with 4 terms:
"ww"⊗"yy"+"ww"⊗"x"+"z"⊗"x"+"z"⊗"yy"
julia> swap(a; coeff = 2)
Linear{Tensor{Tuple{String, String}}, Int64} with 4 terms:
2*"ww"⊗"yy"+2*"ww"⊗"x"+2*"z"⊗"x"+2*"z"⊗"yy"Examples with degrees
The degree of a GradedString (created with the gr"" string macro) is its length.
julia> using LinearCombinations.TestHelpers: GradedString, @gr_str
julia> t = Tensor(gr"x", gr"z")
gr"x"⊗gr"z"
julia> swap(t)
Linear1{Tensor{Tuple{GradedString, GradedString}}, Int64} with 1 term:
-gr"z"⊗gr"x"
julia> a = Linear(gr"x" => 1, gr"yy" => 1) ⊗ Linear(gr"z" => 1, gr"ww" => 1)
Linear{Tensor{Tuple{GradedString, GradedString}}, Int64} with 4 terms:
gr"x"⊗gr"z"+gr"yy"⊗gr"ww"+gr"x"⊗gr"ww"+gr"yy"⊗gr"z"
julia> swap(a)
Linear{Tensor{Tuple{GradedString, GradedString}}, Int64} with 4 terms:
-gr"z"⊗gr"x"+gr"ww"⊗gr"x"+gr"z"⊗gr"yy"+gr"ww"⊗gr"yy"LinearCombinations.Regroup — Type
LinearCombinations.Regroup{A, B}Applying a Regroup object to a Tensor or a linear combinations of tensors rearranges the components of the tensor. Use the regroup"" string macro to create a Regroup object. It is possible to define additional methods to apply Regroup objects to other arguments besides tensors.
See also @regroup_str.
LinearCombinations.@regroup_str — Macro
regroup"a -> b" -> RegroupCreate a Regroup object that can be used to rearrange the components of tensors and possibly other structures.
The actual rearrangement is specified by the two parameters a and b, which are (possibly nested) tuples of integers. These tuples encode the structure of nested tensors, and the integers specify a mapping from the components of the nested source tensor to the nested target tensor. The labels for a and b can in fact be of any isbits type or Symbol instead of Int, but they must be the same for a and b.
The created object rg = regroup"a -> b" is callable. An argument t for rg must be a nested tensor of the same shape as the a tree, and the return value is a Tensor of the same shape as b. The components of the nested tensor t are permuted according to the labels.
If the components of t have non-zero degrees, then rg(t) additionally has a sign according to the usual sign rule: whenever two ojects x and y are swapped, then this incurs the sign (-1)^(deg(x)*(deg(y))). In this case the returned value is of type Linear1 instead of Tensor.
Moreover, rg is linear and can be called with linear combinations of tensors.
Note that for each Regroup element rg, Julia generates separate, efficient code for computing rg(t).
See also swap, @regroup_inv_str, Regroup, LinearCombinations.DefaultCoefftype.
Examples
Example without degrees
julia> rg = regroup"(1, (2, 3), 4) -> ((3, 1), (4, 2))"
Regroup{(1, (2, 3), 4), ((3, 1), (4, 2))}
julia> rg == regroup"(a, (b, c), d) -> ((c, a), (d, b))"
true
julia> t = Tensor("x", Tensor("y", "z"), "w")
"x"⊗("y"⊗"z")⊗"w"
julia> rg(t)
("z"⊗"x")⊗("w"⊗"y")Example with degrees
The degree of a GradedString (created with the gr"" string macro) is its length.
julia> using LinearCombinations.TestHelpers: GradedString, @gr_str
julia> t = Tensor(gr"x", Tensor(gr"y", gr"z"), gr"w")
gr"x"⊗(gr"y"⊗gr"z")⊗gr"w"
julia> rg(t) # same rg as before
Linear1{Tensor{Tuple{Tensor{Tuple{GradedString, GradedString}}, Tensor{Tuple{GradedString, GradedString}}}}, Int64} with 1 term:
-(gr"z"⊗gr"x")⊗(gr"w"⊗gr"y")LinearCombinations.@regroup_inv_str — Macro
regroup_inv"a -> b" -> Tuple{Regroup, Regroup}Create the tuple (regroup"a -> b", regroup"b -> a") containing the Regroup objects for transformations in both directions.
See also @regroup_str.
LinearCombinations.regroup — Function
regroup(a, b) -> RegroupReturn a Regroup object that can be used to rearrange the components of tensors and possibly other structures.
See @regroup_str.
LinearCombinations.regroup_inv — Function
regroup_inv(a, b) -> Tuple{Regroup, Regroup}Return the tuple (regroup(a, b), regroup(b, a)).
See @regroup_inv_str.
Base.transpose — Function
transpose(t::AbstractTensor{T}) where T <: Tuple{Vararg{AbstractTensor}}Return the transpose of a tensor t whose components are tensors of the same length. In other words, the component transpose(t)[i][j] is t[j][i]. If the components t[i][j] may have non-zero degrees, a sign is added according to the usual sign rule. In this case the return type is Linear1 instead of Tensor. The tensor t must have at least one component. If all component tensors are empty, then the empty tensor Tensor() is returned.
This function is linear.
Examples
Example without signs
julia> t = Tensor(Tensor("a", "b", "c"), Tensor("x", "y", "z"))
("a"⊗"b"⊗"c")⊗("x"⊗"y"⊗"z")
julia> transpose(t)
("a"⊗"x")⊗("b"⊗"y")⊗("c"⊗"z")Example with degrees
The degree of a GradedString (created with the gr"" string macro) is its length.
julia> using LinearCombinations.TestHelpers: GradedString, @gr_str
julia> t = Tensor(Tensor(gr"a", gr"b", gr"c"), Tensor(gr"x", gr"y", gr"z"))
(gr"a"⊗gr"b"⊗gr"c")⊗(gr"x"⊗gr"y"⊗gr"z")
julia> transpose(t)
Linear1{Tensor{Tuple{Tensor{Tuple{GradedString, GradedString}}, Tensor{Tuple{GradedString, GradedString}}, Tensor{Tuple{GradedString, GradedString}}}}, Int64} with 1 term:
-(gr"a"⊗gr"x")⊗(gr"b"⊗gr"y")⊗(gr"c"⊗gr"z")Calling tensors
LinearCombinations.AbstractTensor — Method
(tf::AbstractTensor)(tx::AbstractTensor...)Evaluating an AbstractTensor on other AbstractTensors (with the same number of components) is done componentwise. If the degrees of the components or the maps may be non-zero, then the usual sign is introduced: whenever a map f is moved past a component x, then this changes the sign by (-1)^(deg(f)*deg(x)). In this case the return type is Linear1 instead of Tensor if no map returns a linear combination.
Examples
Examples without degrees
julia> @linear f; f(x) = uppercase(x)
f (generic function with 2 methods)
julia> @linear g; g(x) = lowercase(x)
g (generic function with 2 methods)
julia> const h = Tensor(f, g)
f⊗g
julia> a = Linear('x' => 1, 'y' => 2)
Linear{Char, Int64} with 2 terms:
'x'+2*'y'
julia> b = Linear('Z' => -1, 'W' => 3)
Linear{Char, Int64} with 2 terms:
-'Z'+3*'W'
julia> h(Tensor('x', 'Z'))
'X'⊗'z'
julia> h(tensor(a, b))
Linear{Tensor{Tuple{Char, Char}}, Int64} with 4 terms:
-2*'Y'⊗'z'+6*'Y'⊗'w'+3*'X'⊗'w'-'X'⊗'z'
julia> Tensor()(Tensor())
()Examples with degrees
The degree of a GradedString (created with the gr"" string macro) is its length.
julia> using LinearCombinations.TestHelpers: GradedString, @gr_str
julia> using Base: Fix2
julia> j = Tensor(Fix2(*, gr"pp"), Fix2(*, gr"qqq"))
Fix2{typeof(*), GradedString}(*, gr"pp")⊗Fix2{typeof(*), GradedString}(*, gr"qqq")
julia> j(Tensor(gr"x", gr"yy"))
Linear1{Tensor{Tuple{GradedString, GradedString}}, Int64} with 1 term:
-gr"xpp"⊗gr"yyqqq"
julia> a = Linear(gr"x" => 1, gr"yy" => 2)
Linear{GradedString, Int64} with 2 terms:
2*gr"yy"+gr"x"
julia> b = tensor(a, a)
Linear{Tensor{Tuple{GradedString, GradedString}}, Int64} with 4 terms:
gr"x"⊗gr"x"+2*gr"yy"⊗gr"x"+4*gr"yy"⊗gr"yy"+2*gr"x"⊗gr"yy"
julia> j(b)
Linear{Tensor{Tuple{GradedString, GradedString}}, Int64} with 4 terms:
-gr"xpp"⊗gr"xqqq"+2*gr"yypp"⊗gr"xqqq"-2*gr"xpp"⊗gr"yyqqq"+4*gr"yypp"⊗gr"yyqqq"A multilinear example
julia> Tensor(*, *)('a'⊗'b', 'p'⊗'q', 'x'⊗'y')
"apx"⊗"bqy"Other functions accepting tensors
LinearCombinations.deg — Method
deg(t::AbstractTensor)Return the degree of a tensor, which is the sum of the degrees of its components.
See also deg.
Base.:* — Method
*(t1::AbstractTensor , t2::AbstractTensor, ...)Return the product of the tensors, computed from the products of its components. Signs are introduced according to the usual sign rule. If all degrees are integers, then the coefficient type is DefaultCoefftype.
This function is linear.
See also: LinearCombinations.DefaultCoefftype.
Example without degrees
julia> (s, t) = Tensor("ab", "c"), Tensor("x", "yz");
julia> s*t
"abx"⊗"cyz"Example with degrees
The degree of a GradedString (created with the gr"" string macro) is its length.
julia> using LinearCombinations.TestHelpers: GradedString, @gr_str
julia> (s, t) = Tensor(gr"ab", gr"c"), Tensor(gr"x", gr"yz");
julia> s*t
Linear1{Tensor{Tuple{GradedString, GradedString}}, Int64} with 1 term:
-gr"abx"⊗gr"cyz"LinearCombinations.coprod — Method
coprod(t::T) where T <: AbstractTensor -> Linear{Tensor{Tuple{T,T}}}Return the coproduct of a tensor, computed from the coproducts of its components. Signs are introduced according to the usual sign rule. If all degrees are integers, then the coefficient type is DefaultCoefftype.
This function is linear.
See also: coprod, LinearCombinations.DefaultCoefftype.
Example
The degree of a GradedString (created with the gr"" string macro) is its length.
julia> using LinearCombinations.TestHelpers: GradedString, @gr_str
julia> import LinearCombinations: coprod
julia> coprod(x::GradedString) = Linear(Tensor(x[1:k], x[k+1:end]) => 1 for k in 0:length(x));
julia> coprod(gr"xy")
Linear{Tensor{Tuple{GradedString, GradedString}}, Int64} with 3 terms:
gr"x"⊗gr"y"+gr""⊗gr"xy"+gr"xy"⊗gr""
julia> Tensor(gr"x", gr"y") |> coprod
Linear{Tensor{Tuple{Tensor{Tuple{GradedString, GradedString}}, Tensor{Tuple{GradedString, GradedString}}}}, Int64} with 4 terms:
(gr"x"⊗gr"y")⊗(gr""⊗gr"")+(gr"x"⊗gr"")⊗(gr""⊗gr"y")-(gr""⊗gr"y")⊗(gr"x"⊗gr"")+(gr""⊗gr"")⊗(gr"x"⊗gr"y")LinearCombinations.diff — Method
diff(t::T) where T <: AbstractTensor -> Linear{T}Return the differential of the tensor t by differentiating each tensor factor at a time and adding signs according to the degrees of the components. The coefficient type is usually DefaultCoefftype. However, if the degrees of the tensor components are not integers, then the coefficient type is chosen such that it can accommodate the signs.
See also diff, LinearCombinations.DefaultCoefftype.
Example
The degree of a GradedString (created with the gr"" string macro) is its length.
julia> using LinearCombinations.TestHelpers: GradedString, @gr_str
julia> import LinearCombinations: diff
julia> diff(x::GradedString) = Linear1(gr"δ"*x => Int(x[1] != 'δ'));
julia> gr"x" |> diff
Linear1{GradedString, Int64} with 1 term:
gr"δx"
julia> gr"x" |> diff |> diff
Linear1{GradedString, Int64} with 0 terms:
0
julia> Tensor(gr"x", gr"yy", gr"zzz") |> diff
Linear{Tensor{Tuple{GradedString, GradedString, GradedString}}, Int64} with 3 terms:
gr"δx"⊗gr"yy"⊗gr"zzz"-gr"x"⊗gr"δyy"⊗gr"zzz"-gr"x"⊗gr"yy"⊗gr"δzzz"Twisted tensors
LinearCombinations.LeftTwistedTensor — Type
LeftTwistedTensor{X,Y,TWC}See also RightTwistedTensor, lefttwistedtensor.
LinearCombinations.RightTwistedTensor — Type
RightTwistedTensor{X,Y,TWC}See also LeftTwistedTensor, righttwistedtensor.
LinearCombinations.lefttwistedtensor — Function
lefttwistedtensor(twc)Return a callable object that converts an AbstractTensor to a LeftTwistedTensor with twisting cochain twc. The callable object is linear.
See also LeftTwistedTensor, righttwistedtensor.
Example
julia> @linear twc; # some twisting cochain
julia> t = Tensor("x", "y") |> lefttwistedtensor(twc)
"x"⊗˱"y"
julia> typeof(t)
LeftTwistedTensor{String, String, typeof(twc)}LinearCombinations.righttwistedtensor — Function
righttwistedtensor(twc)Return a callable object that converts an AbstractTensor to a RightTwistedTensor with twisting cochain twc. The callable object is linear.
See also RightTwistedTensor, lefttwistedtensor.
Example
julia> @linear twc; # some twisting cochain
julia> t = Tensor("x", "y") |> righttwistedtensor(twc)
"x"⊗˲"y"
julia> typeof(t)
RightTwistedTensor{String, String, typeof(twc)}