6.4: D- Numerical Tensor Products
( \newcommand{\kernel}{\mathrm{null}\,}\)
This appendix discusses how tensor products are handled in numerical linear algebra software. We will focus on Python with the Numeric Python (numpy) module. The discussion is also applicable, with minor modifications, to GNU Octave or Matlab. We assume the reader is familiar with the basics of Python/Numpy, e.g. how vectors can be represented by 1D arrays, linear operators (matrices) can be represented by 2D arrays, etc.
Tensor products are implemented by the numpy.kron
function, which performs an operation called a Kronecker product. The function takes two inputs, which can be 1D arrays, 2D arrays, or even higher-dimensional arrays (which we won’t discuss). It returns a new array representing the tensor product of the inputs, whose dimensionality depends on that of the inputs. The function can be used to compute products of vectors (|a⟩⊗|b⟩), products of operators (ˆOA⊗ˆOB), etc. It can even compute “mixed” products like |a⟩⊗ˆOB, which is useful for calculating partial projections and partial traces.
In the next few sections, we will prove that the various tensor products of bras, kets, and operators can be represented using the following Numpy expressions involving numpy.kron
:
Definition: Numpy Expressions
|a⟩⊗|b⟩↔kron(a, b)⟨a|⊗⟨b|↔kron(a.conj(), b.conj())ˆA⊗ˆB↔kron(A, B)|a⟩⊗ˆB↔kron(a, B.T).T⟨a|⊗ˆB↔kron(a.conj(), B)ˆA⊗|b⟩↔kron(A.T, b).TˆA⊗⟨b|↔kron(A, b.conj())
D.1 Products of Vectors
Suppose a and b are both 1D arrays, of length M and N respectively; let their components be (a0,a1,…,aM−1) and (b0,b1,…,bN−1). Following Numpy conventions, we do not explicitly distinguish between “row vectors” and “column vectors”, and component indices start from 0. The Kronecker product between a and b generates the following 1D array:
kron(a,b)=(a0b0,…,a0bN−1,a1b0,…,a1bN−1,…,aM−1bN−1).
We can think of this as taking each component of a, and multiplying it by the entire b array:
kron(a,b)=(a0b,a1b,…,aM−1b).
As we shall see, this description of the Kronecker product extends to higher-dimensional arrays as well. In the present case, a and b are both 1D, and the result is a 1D array of MN components, which can be described compactly in index notation by
[kron(a,b)]μ=ambnwhereμ=mN+n.
The index μ is defined so that as we sweep through m=0,…,M−1 and n=0,…,N−1, μ runs through the values 0,1,…,MN−1 without duplication. Note, by the way, that the order of inputs into kron is important: kron(a,b) is not the same as kron(b,a)! The asymmetry between a and b is apparent in the definitions (???) and (???).
In terms of abstract linear algebra (as used in quantum theory), let HA be an M-dimensional space with basis {|m⟩}, and HB be an N-dimensional space with basis {|n⟩}. Any two vectors |a⟩∈HA and |b⟩∈HB can be written as
|a⟩=M−1∑m=0am|m⟩,|b⟩=N−1∑n=0bn|n⟩.
A natural basis for the product space HA⊗HB is
{|μ⟩≡|m⟩|n⟩}where{μ=mN+nm=0,1,…,M−1n=0,1,…,N−1.
Using Equation (???), we can show that
|a⟩⊗|b⟩=∑mnambn|m⟩|n⟩=MN−1∑μ=0[kron(a,b)]μ|μ⟩.
Therefore, we need only remember that the tensor product of two kets is represented by
|a⟩⊗|b⟩↔kron(a,b).
Likewise, for bras,
⟨a|⊗⟨b|↔kron(a∗,b∗).
D.2 Products of Matrices
Let A and B be 2D arrays of size M×M and N×N respectively:
A=[A00⋯A0,M−1⋮⋱⋮AM−1,0⋯AM−1,M−1],B=[B00⋯B0,N−1⋮⋱⋮BN−1,0⋯BN−1,N−1].
Then the Kronecker product of A and B is an MN×MN array of the form
kron(A,B)=[A00B⋯A0,M−1B⋮⋱⋮AM−1,0B⋯AM−1,M−1B].
As before, this can be interpreted as taking each component of A, and multiplying it by B. The result can be written using index notation as
[kron(A,B)]μμ′=Amm′Bnn′whereμ=mN+n,μ′=m′N+n′.
In the language of abstract linear algebra, let HA and HB again be spaces with bases {|m⟩} and {|n⟩}. Consider two linear operators ˆA and ˆB acting respectively on these spaces:
ˆA=M−1∑m,m′=0|m⟩Amm′⟨m′|,ˆB=N−1∑n,n′=0|n⟩Bnn′⟨n′|.
Then we can show using Equation (???) that
ˆA⊗ˆB=∑mm′nn′|m⟩|n⟩Amm′Bnn′⟨m′|⟨n′|=∑μ,μ′|μ⟩[kron(A,B)]μμ′⟨μ′|,
where {|μ⟩} is the basis for HA⊗HB previously defined in Equation (???). Thus,
ˆA⊗ˆB↔kron(A,B).
This result, like Equation (???), is nice because it means that we can relegate the handling of tensor product components entirely to the kron
function. So long as we make a particular basis choice for the spaces HA and HB, and keep to that choice, kron
will return the vector products and operator products expressed using an appropriate and natural basis for HA⊗HB [i.e., the basis defined in Equation (???)].
D.3 Mixed Products
For “mixed” products of operators with bras or kets, the representation using kron
is more complicated, but only slightly. First, consider the 1D array a and 2D array B:
a=(a0,…,aM−1),B=[B00⋯B0,N−1⋮⋱⋮BN−1,0⋯BN−1,N−1].
Then the Kronecker product between the two is
kron(a,B)=(a0B,a1B,…,aM−1B).
Note that a is explicitly treated as a row vector. In component terms,
kron(a,B)]nμ′=am′Bnn′,whereμ′=m′N+n′.
In linear algebraic terms, let
|a⟩=∑mam|m⟩,ˆB=∑nn′|n⟩Bnn′⟨n′|.
Then
|a⟩⊗ˆB=∑μn′|μ⟩amBnn′⟨n′|,μ=mN+n.
This does not quite match Equation (???)! The basic problem is that the Kronecker product treats a a row vector. However, we can patch things up by massaging Equation (???) a bit:
[kron(a,BT)T]μn′=[kron(a,BT)]n′μ=am(BT)n′nwhereμ′=m′N+n′=amBnn′.
This is an appropriate match for Equation (6.4.22), so we conclude that
|a⟩⊗ˆB↔kron(a,BT)T.
To take the product using the bra ⟨a|, we replace Equation (6.4.22) by
⟨a|⊗ˆB=∑nμ′|n⟩a∗m′Bnn′⟨μ′|,μ′=m′N+n′.
Comparing this to Equation (???) yields
⟨a|⊗ˆB↔kron(a∗,B).
Likewise, consider the 2D array A and 1D array b:
A=[A00⋯A0,M−1⋮⋱⋮AM−1,0⋯AM−1,M−1],b=(b0,…,bN−1).
Then the Kronecker product is
kron(A,b)=[A00b⋯A0,M−1b⋮⋱⋮AM−1,0b⋯AM−1,M−1b].
Similar to before, b is treated as a row vector. In component terms,
[kron(A,B)]mμ′=Amm′bn′,whereμ′=m′N+n′.
Using the same procedure as before, we can straightforwardly show that
ˆA⊗|b⟩=∑μm′|μ⟩[kron(AT,b)T]μm′⟨m′|↔kron(AT,b)TˆA⊗⟨b|=∑mμ′|m⟩[kron(A,b∗)]mμ′⟨μ′|↔kron(A,b∗).