Distances of Distances
PortfolioOptimisers.DistanceDistance — Type
struct DistanceDistance{__T_metric, __T_args, __T_kwargs, __T_power, __T_alg} <: AbstractDistanceEstimatorMeasures how differently two assets relate to the whole universe, by applying a metric to a distance matrix.
Two assets are close under this estimator when their columns of the base distance matrix are close — that is, when they stand at similar distances from every other asset. This is a second-order reading: it can separate two assets that are equally far apart under Distance but occupy different positions in the universe. It wraps a metric from Distances.jl around a base Distance built from power and alg.
power = 1 reproduces the base distance exactly, so the distance-of-distances matrix is the same as at power = nothing. Only $p \geq 2$ changes the result. See Distance for the formula of each algorithm.
Mathematical definition
\[\begin{align} _{g}\tilde{d}_{i,\,j} &= \lVert_{g}\boldsymbol{D}_{i} - _{g}\boldsymbol{D}_{j}\rVert\,, \end{align}\]
Where:
- $_{g}\tilde{d}_{i,\,j}$: General distance of distances between assets $i$ and $j$.
- $_{g}\boldsymbol{D}_{i}$: Column $i$ of the generalised distance matrix (see
AbstractDistanceAlgorithm). - $\lVert \cdot \rVert$: Metric used to compute the distance of distances,
metric.
The source states this at the default metric, the Euclidean norm. A base distance matrix is symmetric, so the column and the row give the same answer.
Fields
metric: Distance metric used for the distances of distances computations.
args: Additional positional arguments for the distances of distances metric.
kwargs: Additional keyword arguments for the distances of distances metric.
power: Optional matrix exponent.nothingand1both give the base distance, so onlypower >= 2changes the result.
alg: Distance algorithm.
Constructors
DistanceDistance(; metric::Distances.Metric = Distances.Euclidean(), args::Tuple = (), kwargs::NamedTuple = (;), power::Option{<:Integer} = nothing, alg::AbstractDistanceAlgorithm = SimpleDistance()) -> DistanceDistanceKeywords correspond to the struct's fields. power and alg are forwarded to a Distance, so they carry the meaning and the defaults documented there.
Validation
- If
poweris notnothing,power >= 1.
Examples
julia> DistanceDistance()DistanceDistance metric ┼ Distances.Euclidean: Distances.Euclidean(0.0) args ┼ Tuple{}: () kwargs ┼ @NamedTuple{}: NamedTuple() power ┼ nothing alg ┴ SimpleDistance()The Euclidean norm of two columns of a bounded distance matrix is not itself bounded by 1.
ComplementSimilarity is therefore out of domain against this estimator's own default, and assert_similarity_domain refuses the pair on the PMFG path. Use ExponentialSimilarity or GeneralExponentialSimilarity, which have no domain.
Related
References
- [5] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Section 12.1.1, Equation 12.1.
PortfolioOptimisers.distance — Method
distance(de::DistanceDistance, ce::StatsBase.CovarianceEstimator, X::MatNum;
dims::Int = 1, kwargs...)Compute the distance-of-distances matrix from a covariance estimator and data matrix.
Algorithm
- Build a base
Distancecarryingde.powerandde.alg, and calldistanceon it withce,X,dimsandkwargs, giving the base distance matrixD. - Apply
de.metrictoDwithDistances.pairwise, forwarding the estimator's ownde.argsandde.kwargs, giving the distance-of-distances matrix.
An alg of CanonicalDistance redirects inside step 1, by the type of ce, so the algorithm that produces D is chosen before the metric is applied. distance carries the redirect table.
Distances.pairwise treats a column of D as one observation. The call passes dims = 2 itself, before the splat of de.kwargs, so a dims in de.kwargs overrides it. Which axis is read does not change the answer here, because a base distance matrix is symmetric. It matters only when de.args supplies a second matrix of a different shape.
Arguments
de: Distance-of-distances estimator.ce: Covariance estimator.X: Data matrix (observations × assets).dims: Dimension along which to perform the computation.kwargs...: Additional keyword arguments passed to the base distance computation of step 1. They never reachDistances.pairwise, which is served by thekwargsfield ofde.
Returns
D::Matrix{<:Number}: Matrix of pairwise distances of distances.
Related
PortfolioOptimisers.distance — Method
distance(de::DistanceDistance, rho::MatNum, args...; kwargs...)Compute the distance-of-distances matrix from a correlation or covariance matrix.
Algorithm
- Build a base
Distancecarryingde.powerandde.alg, and calldistanceon it withrho,argsandkwargs, giving the base distance matrixD. - Apply
de.metrictoDwithDistances.pairwise, forwarding the estimator's ownde.argsandde.kwargs, giving the distance-of-distances matrix.
An alg of CanonicalDistance takes one step before step 1, and rebuilds itself with SimpleDistance. There is no covariance estimator on this route, so the redirect table cannot select a row and its fallback is taken.
Distances.pairwise reads the columns of D, as it does on the covariance-estimator route above. The call passes dims = 2 itself, and a dims in de.kwargs overrides it.
Arguments
de: Distance-of-distances estimator.rho: Correlation or covariance matrix.args...: Additional arguments. They are forwarded to the base distance of step 1, which ignores them. They are not theargsfield ofde, which is what reachesDistances.pairwise.kwargs...: Additional keyword arguments passed to the base distance computation of step 1. They never reachDistances.pairwise, which is served by thekwargsfield ofde.
Returns
D::Matrix{<:Number}: Matrix of pairwise distances of distances.
Related
PortfolioOptimisers.cor_and_dist — Method
cor_and_dist(de::DistanceDistance, ce::StatsBase.CovarianceEstimator, X::MatNum;
dims::Int = 1, kwargs...)Compute both the correlation matrix and the distance-of-distances matrix from a covariance estimator and data matrix.
Algorithm
- Build a base
Distancecarryingde.powerandde.alg, and callcor_and_diston it withce,X,dimsandkwargs, giving the correlation matrixrhoand the base distance matrixDfrom one pass. This is the pass that thedistancesibling cannot share. - Apply
de.metrictoDwithDistances.pairwise, forwarding the estimator's ownde.argsandde.kwargs, giving the distance-of-distances matrix. - Return
rhounchanged beside that matrix. The metric is applied to the distance matrix alone, so the correlation this method returns is the base estimator's own.
The second element is the matrix that distance returns for the same de, ce and X, so a caller that needs both quantities pays for one correlation rather than two.
Arguments
de: Distance-of-distances estimator.ce: Covariance estimator.X: Data matrix (observations × assets).dims: Dimension along which to perform the computation.kwargs...: Additional keyword arguments passed to the base distance computation of step 1. They never reachDistances.pairwise, which is served by thekwargsfield ofde.
Returns
(rho::Matrix{<:Number}, D::Matrix{<:Number}): Tuple of correlation matrix and distance-of-distances matrix.
Related
References
- [5]
- D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025).