Skip to content

Bases and variance

This is the one chapter with no counterpart in the Echoes manual, which works exclusively in an orthonormal frame and states outright that "introducing the notion of tensor variance is useless here". TensND does not make that assumption: a tensor carries a basis, which may be arbitrary, and a variance tuple saying how each of its indices transforms. Everything below is derived from the definitions and matches src/bases.jl.

Dual basis and metric

Let be a basis of , not necessarily orthogonal or normalized. The dual (reciprocal) basis is defined by

The two metric matrices are the Gram matrices of each basis,

so that  . They raise and lower indices, and convert between the two bases:

Variance of components

A vector has two equally legitimate sets of components,

are the contravariant components (:cont, the default in TensND) and the covariant ones (:cov). An order- tensor has one such choice per index, hence a variance tuple of length ; for an order-2 tensor all four combinations exist:

related by the metric,   and so on. In TensND the conversion is components(t, var), or change_tens(t, ℬ, var) when the basis changes too.

Why an identity looks like a metric

Storing the covariant metric as a twice-covariant tensor and asking for its mixed components necessarily returns the identity, because  . That round trip is the example in the Tens docstring and the cheapest sanity check on a basis.

Change of basis

If    — that is, has the new basis vectors as columns in the old basis — then components transform oppositely to basis vectors for a contravariant index and with them for a covariant one:

This contravariance/covariance split is exactly what the words name, and it is what makes the distinction vanish for an orthonormal basis, where   and   .

The four matrices of a Basis

TensND stores all four objects rather than recomputing them, because every component conversion needs one of them:

Stored matrixSymbolMeaning
vecbasis(ℬ, :cov)columns = basis vectors in the canonical basis
vecbasis(ℬ, :cont)columns = dual basis vectors
metric(ℬ, :cov)covariant metric
metric(ℬ, :cont)contravariant metric,

The basis hierarchy

The more structure a basis has, the less of the above needs to be computed — so the type of the basis fixes the cost of every operation on tensors expressed in it, and the constructor Basis automatically returns the most specific type that applies.

TypeMetricDual basisVariance matters?
CanonicalBasisitselfno
RotatedBasisitselfno
OrthogonalBasis yes, but diagonally
Basisfullyes

RotatedBasis is built from one angle in 2-D or three Euler angles in 3-D (see Rotations); OrthogonalBasis from an orthonormal basis and a tuple of scaling factors . Those are precisely the Lamé coefficients when the basis is the natural basis of a curvilinear coordinate system — the link is made on Curvilinear differential calculus.

Correspondingly, a tensor's type follows its basis' type: Tens, TensOrthogonal, TensRotated, TensCanonical. Only the first two carry a variance tuple.

Normalization

Dividing each vector of a basis by its norm produces an orthogonal basis with unit vectors, i.e. an orthonormal one if the original was orthogonal. This is LinearAlgebra.normalize``(ℬ) and it is what relates the natural basis of a coordinate system to its normalized basis — the distinction that makes    rather than , and the source of every Lamé coefficient in Curvilinear differential calculus.

For a general (non-orthogonal) basis, normalizing removes the scaling but not the obliquity: the metric becomes a correlation matrix with unit diagonal, and variance still matters.