Distance

PortfolioOptimisers.DistanceType
struct Distance{__T_power, __T_alg} <: AbstractDistanceEstimator

Pairs a distance algorithm with an optional integer power, and applies it to a correlation matrix or to the data.

This is the estimator every clustering, network and phylogeny routine reaches for a distance matrix. alg chooses the transform; power raises the quantity that transform is built on to the integer power $p$, which sharpens the contrast between a strong relationship and a weak one.

Note

power = 1 reproduces the base distance exactly, for every algorithm. It is the neutral position of the knob, not a way to select the generalised estimator. Only $p \geq 2$ changes the result. power = nothing and power = 1 are kept apart by dispatch alone, so that the base case never raises a matrix to a power.

Mathematical definition

The four correlation-based algorithms (see RhoDistanceAlgorithm) raise the correlation to $p$ inside their own base formula.

\[\begin{align} _{g}d_{i,\,j}^{\mathrm{S}} &= \sqrt{\mathrm{clamp}\left(s\left(1 - \rho_{i,\,j}^{p}\right),\, 0,\, 1\right)}\\ _{g}d_{i,\,j}^{\mathrm{SA}} &= \sqrt{\mathrm{clamp}\left(1 - \lvert\rho_{i,\,j}\rvert^{p},\, 0,\, 1\right)}\\ _{g}d_{i,\,j}^{\mathrm{L}} &= \max\left(-\log{\lvert\rho_{i,\,j}\rvert^{p}},\, 0\right)\\ _{g}d_{i,\,j}^{\mathrm{C}} &= \sqrt{\mathrm{clamp}\left(1 - \rho_{i,\,j}^{p},\, 0,\, 1\right)}\\ s &= \begin{cases} 1/2 & \text{if } p \mod 2 \neq 0\\ 1 & \text{otherwise} \end{cases}\,, \end{align}\]

VariationInfoDistance has no correlation to raise, so it raises the distance itself.

\[\begin{align} _{g}d_{i,\,j}^{\mathrm{VI}} &= \left(d_{i,\,j}^{\mathrm{VI}}\right)^{p}\,, \end{align}\]

Where:

The two cases of $s$ are not a convention. $s$ is the normalisation that keeps the radicand inside $[0,\,1]$ over the reachable range of $\rho_{i,\,j}^{p}$, so it is $1 / (1 - m)$, where $m$ is the smallest value $\rho_{i,\,j}^{p}$ can take. An odd $p$ keeps the sign, so $m = -1$ and $s = 1/2$. An even $p$ cannot be negative, so $m = 0$ and $s = 1$.

The clamp is inert for the first two algorithms at every $p$: $s(1 - \rho_{i,\,j}^{p})$ and $1 - \lvert\rho_{i,\,j}\rvert^{p}$ never leave $[0,\,1]$. It binds for CorrelationDistance at every odd $p$, where $\rho_{i,\,j}^{p}$ keeps its sign and the radicand runs over $[0,\,2]$; that algorithm's own docstring measures the truncation.

CanonicalDistance is a redirect and owns no formula. It forwards power to the algorithm it selects.

`power` raises two different quantities

The field is one field, and the reader must not assume one meaning. For a correlation-based algorithm it raises the correlation, inside the transform. For VariationInfoDistance there is no correlation to raise, so it raises the distance the algorithm returns. So $_{g}d^{\mathrm{S}}$ at $p = 2$ is not $\left(d^{\mathrm{S}}\right)^{2}$, while $_{g}d^{\mathrm{VI}}$ at $p = 2$ is $\left(d^{\mathrm{VI}}\right)^{2}$.

The source carries the four base formulas alone. Section 6.2 of the reference below ends at the tail dissimilarity, so the $p$ generalisation and the scaling $s$ are this library's own extension of it.

Fields

  • power: Optional matrix exponent. nothing and 1 both give the base distance, so only power >= 2 changes the result.
  • alg: Distance algorithm.

Constructors

Distance(;    power::Option{<:Integer} = nothing,    alg::AbstractDistanceAlgorithm = SimpleDistance()) -> Distance

Keywords correspond to the struct's fields.

Why the default `alg` is `SimpleDistance`

CanonicalDistance picks an algorithm from the covariance estimator, and falls back to SimpleDistance when the estimator carries no preference. A bare Distance() also serves the matrix entry point distance(de, rho), which holds no estimator to pick from. The two therefore agree except on the estimators CanonicalDistance treats specially. Library entry points that always hold a covariance estimator default to Distance(; alg = CanonicalDistance()) instead, so that the special cases are honoured.

Validation

  • If power is not nothing, power >= 1.

Examples

julia> Distance()Distance  power ┼ nothing    alg ┴ SimpleDistance()

Related

References

  • [4] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Section 6.2.
source
PortfolioOptimisers.distanceFunction
distance(de::Distance{<:Any,
                      <:Union{<:SimpleDistance, <:SimpleAbsoluteDistance, <:LogDistance,
                              <:CorrelationDistance, <:CanonicalDistance}},
         ce::StatsBase.CovarianceEstimator, X::MatNum; dims::Int = 1, kwargs...)

Compute the correlation matrix with ce and X, and transform it into a distance matrix with the algorithm de names.

This is the data entry point of the correlation-based family. cor_and_dist is the same computation with the correlation returned alongside the distance, so a caller that needs both pays for the correlation once.

Algorithm

  1. Compute the correlation matrix from ce and X with Statistics.cor, along dims. kwargs are forwarded to it, and it is what refuses a dims outside $(1,\, 2)$.
  2. Transform that correlation matrix with _dist_from_cor, under de.alg and de.power.

A CanonicalDistance de takes one step first: it rebuilds de with SimpleDistance, carrying de.power over, because a ce that is a plain StatsBase.CovarianceEstimator carries no preference. The four estimators that do carry one have their own methods; see the redirect table on CanonicalDistance.

Arguments

  • de: Distance estimator.

  • ce: Covariance estimator.

  • X: Data matrix (observations × assets).

  • dims: Dimension along which to perform the computation.

  • kwargs...: Additional keyword arguments passed to the correlation computation.

Validation

  • dims in (1, 2).

Returns

  • D::MatNum: Distance matrix assets x assets, in the units the distance algorithm defines.

Details

  • dims is enforced by Statistics.cor, not by this method. A dims outside $(1,\, 2)$ raises a DomainError from there.

Related

source
distance(de::Distance{Nothing, <:VariationInfoDistance}, ::Any, X::MatNum;
         dims::Int = 1, kwargs...)
distance(de::Distance{<:Integer, <:VariationInfoDistance}, ::Any, X::MatNum;
         dims::Int = 1, kwargs...)

Compute the variation of information distance matrix from the data matrix alone.

This is the one algorithm of the family that reads X rather than a correlation matrix, so the covariance estimator is a placeholder that the method ignores. It captures a non-linear relationship that no correlation coefficient sees.

`power` raises the distance here, not the correlation

The two methods above are the two power cases, and they are the reason the trap exists. For a correlation-based algorithm power raises the correlation inside the transform. There is no correlation here, so power raises the distance the algorithm returns: the result is variation_info(...) .^ de.power. One field, two quantities.

Algorithm

  1. Orient X with dims_oriented, which transposes it when dims is 2 and refuses any other value.
  2. Read de.alg.bins and de.alg.normalise off the algorithm, and pass both to variation_info, which builds the joint histograms and forms the distance. VariationInfoDistance states those steps.
  3. When de.power is an Integer, raise the distance matrix of step 2 to it entry by entry. When de.power is nothing, return that matrix as it stands.

Arguments

  • de: Distance estimator carrying the VariationInfoDistance algorithm.
  • ::Any: Covariance estimator placeholder for API compatibility. It is ignored.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments. They are ignored.

Validation

  • dims in (1, 2).

Returns

  • D::MatNum: Distance matrix assets x assets, in the units the distance algorithm defines.

Details

Related

source
distance(::Distance{<:Any,
                    <:Union{<:SimpleDistance, <:SimpleAbsoluteDistance, <:LogDistance,
                            <:CorrelationDistance, <:CanonicalDistance}},
         rho::MatNum, args...; kwargs...)

Compute the distance matrix from a correlation matrix, or from a covariance matrix.

This is the matrix entry point of the correlation-based family, for a caller that already holds the matrix and needs no covariance estimator. The value of the diagonal decides which of the two it was given; see _as_correlation.

Algorithm

  1. Coerce rho to a correlation matrix with _as_correlation, which also checks that it is square.
  2. Transform that correlation matrix with _dist_from_cor, under de.alg and de.power.

A CanonicalDistance de takes one step first: it rebuilds de with SimpleDistance, carrying de.power over. There is no covariance estimator here to select from, so the redirect table cannot apply and the fallback of the table is taken.

Arguments

  • de: Distance estimator.

  • rho: Correlation or covariance matrix.

  • args...: Additional arguments (ignored).

  • kwargs...: Additional keyword arguments. They are ignored.

Validation

  • rho is square.

Returns

  • D::MatNum: Distance matrix assets x assets, in the units the distance algorithm defines.

Details

  • The distance is the one the algorithm defines, and it is not Euclidean under any of the four. SimpleDistance and SimpleAbsoluteDistance return an angular distance, and LogDistance an unbounded dissimilarity.
  • A covariance matrix is converted with StatsBase.cov2cor, and the conversion allocates rather than writing into the argument.
  • args and kwargs exist so that this method and the ce-and-X method above take the same call. Neither is read.

Related

source
distance(de::Distance{<:Any, <:CanonicalDistance},
         ce::Union{<:MutualInfoCovariance,
                   <:AllInternalMutualInfoCov,
                   <:LTDCov_AllInternalLTDCov,
                   <:DistCov_AllInternalDistCov},
         X::MatNum; dims::Int = 1, kwargs...)

Rebuild de with the distance algorithm that the covariance estimator's own range calls for, and call distance again.

The redirect owns no formula. It exists so that a codependence measure reaches the transform its range needs: a signed correlation must be halved, a mutual information has no correlation to transform at all, and a tail dependence coefficient wants an unbounded distance. de.power is carried over unchanged onto the algorithm that is selected.

Covariance estimatorAlgorithm selectedRead from ce
MutualInfoCovarianceVariationInfoDistancece.bins, ce.normalise
PortfolioOptimisersCovariance wrapping itVariationInfoDistancece.ce.bins, ce.ce.normalise
LowerTailDependenceCovariance, wrapped or notLogDistancenothing
DistanceCovariance, wrapped or notCorrelationDistancenothing
any other StatsBase.CovarianceEstimatorSimpleDistancenothing

Algorithm

  1. Select the row of the table above by the type of ce. Dispatch does the selection, so a wrapper reaches the same row as the estimator it wraps.
  2. Build a fresh Distance carrying de.power and the algorithm of that row.
  3. On the two mutual-information rows, copy bins and normalise off ce onto the new VariationInfoDistance, one field level deeper for the wrapper. Without the copy the algorithm would take its own defaults, and the distance would be a different number.
  4. Call distance with the rebuilt estimator, the same ce, and the same X, dims and kwargs.

Arguments

  • de: Distance estimator carrying the CanonicalDistance algorithm.
  • ce: Covariance estimator.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments passed to the selected algorithm.

Returns

  • D::MatNum: Distance matrix assets x assets, in the units the distance algorithm defines.

Details

  • Step 3 is invisible to a reader of the signature, and it is load-bearing. A MutualInfoCovariance built with a non-default bins gives a different distance matrix from one built with the default, and the redirect is what carries that setting across.
  • The last row is the fallback, and it is also what a bare Distance with SimpleDistance gives. The two agree on every estimator outside the table.
  • cor_and_dist carries the same table, over the same five rows.

Related

source
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.

This method first computes a base distance matrix using Distance with the specified power and algorithm, then applies the provided metric to compute a second-level distance matrix.

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.

Returns

  • D::Matrix{<:Number}: Matrix of pairwise distances of distances.

Related

source
distance(de::DistanceDistance, rho::MatNum, args...; kwargs...)

Compute the distance-of-distances matrix from a correlation or covariance matrix.

This method first computes a base distance matrix using Distance with the specified power and algorithm, then applies the provided metric to compute a second-level distance matrix.

Arguments

  • de: Distance-of-distances estimator.
  • rho: Correlation or covariance matrix.
  • args...: Additional arguments (ignored).
  • kwargs...: Additional keyword arguments passed to the base distance computation.

Returns

  • D::Matrix{<:Number}: Matrix of pairwise distances of distances.

Related

source
distance(de::FeatureDistance, Z::MatNum; dims::Int = 1, kwargs...)
distance(de::FeatureDistance, Z::Arr3Num; dims::Int = 1, kwargs...)

Compute the distance matrix from a feature matrix.

Arguments

  • de: Feature distance estimator.
  • Z: Feature matrix assets × features if dims = 1, features × assets when dims = 2. May also be a 3-D array of time-varying features, in which case the observation axis always leads: observations × assets × features if dims = 1, observations × features × assets when dims = 2.
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments (ignored).

Validation

  • dims in (1, 2).
  • !isempty(Z).
  • all(isfinite, Z).
  • Z lies in de.metric's domain (see assert_metric_domain).

Returns

  • D::Matrix{<:Number}: Matrix of pairwise distances, assets × assets.

Details

  • The 2-D method never consults de.alg: a static feature matrix has no observation axis to collapse, so the collapse algorithm is inert rather than an error. The 3-D method dispatches on it.
  • Assets whose feature vector is entirely zero are given the convention documented in patch_zero_feature_vectors!.

Examples

julia> Z = [1.0 0.0; 0.0 1.0; 1.0 1.0];julia> distance(FeatureDistance(), Z)3×3 Matrix{Float64}: 0.0   0.5   0.25 0.5   0.0   0.25 0.25  0.25  0.0

Related

source
distance(de::FeatureDistance, ::Any, ::Any; Z::Option{<:ArrNum} = nothing,
         z_src::Symbol = :none, kwargs...)
cor_and_dist(de::FeatureDistance, ::Any, ::Any; Z::Option{<:ArrNum} = nothing,
             z_src::Symbol = :none, kwargs...)

Three-argument entry points, for the clustering and network estimators.

Every consumer in the clustering and network stack calls cor_and_dist(de, ce, X; …) or distance(de, pl, X; …), passing a covariance estimator (or, in logo!'s case, a similarity matrix) and a returns matrix. FeatureDistance uses neither: it measures a feature matrix, which travels beside them on the Z keyword argument, resolved from a carrier by feature_matrix_picker. Both positionals are therefore ignored, and typed ::Any rather than bounded — logo! puts a similarity matrix where the others put a covariance estimator.

Details

  • dims is ignored and the kernel is called with dims = 1. The ambient dims describes the returns matrix X, and a carried Z is canonically assets-major regardless of it. dims stays meaningful only at the raw-matrix entry point distance(de, Z; dims).
  • A missing Z throws IsNothingError naming z_src (see assert_feature_matrix_supplied).

Related

source
PortfolioOptimisers.cor_and_distFunction
cor_and_dist(de::Distance{<:Any,
                          <:Union{<:SimpleDistance, <:SimpleAbsoluteDistance,
                                  <:LogDistance, <:CorrelationDistance,
                                  <:VariationInfoDistance, <:CanonicalDistance}},
             ce::StatsBase.CovarianceEstimator, X::MatNum; dims::Int = 1, kwargs...)

Compute the correlation matrix and the distance matrix together, from one pass over the data.

It returns the same D that distance returns for the same arguments; that agreement is the claim of having two entry points. Take this one when both matrices are wanted, because the correlation-based family then computes the correlation once instead of twice.

Algorithm

Which of the three routes runs is decided by de.alg.

  1. A correlation-based algorithm computes the correlation matrix with Statistics.cor, then transforms that same matrix with _dist_from_cor. This is the route that saves the second correlation.
  2. VariationInfoDistance checks dims with assert_dims, computes the correlation matrix for the caller, and calls distance for the distance. The distance reads X, not the correlation, so nothing is shared between the two.
  3. CanonicalDistance rebuilds de with the algorithm its redirect table names for ce, then re-enters at route 1 or route 2. See distance for the table and for the fields the rebuild copies.

Arguments

  • de: Distance estimator.
  • ce: Covariance estimator.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments passed to the correlation computation.

Validation

  • dims in (1, 2).

Returns

  • rho::MatNum: Correlation matrix assets x assets.
  • D::MatNum: Distance matrix assets x assets, in the units the distance algorithm defines.

Details

  • Route 2 checks dims itself with assert_dims. Route 1 leaves the check to Statistics.cor, which raises the same DomainError.
  • The correlation returned is the one ce computes, untransformed. It is not the magnitude that SimpleAbsoluteDistance and LogDistance take, nor the power of it that a de.power raises.

Related

source
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.

This method first computes the correlation and base distance matrices using Distance, then applies the provided metric to the base distance matrix.

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.

Returns

  • (rho::Matrix{<:Number}, D::Matrix{<:Number}): Tuple of correlation matrix and distance-of-distances matrix.

Related

source
cor_and_dist(de::FeatureDistance, Z::MatNum; dims::Int = 1, kwargs...)
cor_and_dist(de::FeatureDistance, Z::Arr3Num; dims::Int = 1, kwargs...)

Compute the similarity and distance matrices from a feature matrix.

The similarity shares the distance's provenance: it is distance_to_similarity(de.sim; D = D), derived from the distance matrix this call just produced, so S and D are two views of one measurement rather than two independent estimates. Deriving it from the aggregated distance is also what keeps the zero-feature-vector convention consistent under AggregateDistances, since $\mathrm{mean}(\cos(\pi D_{t})) \neq \cos(\pi\,\mathrm{mean}(D_{t}))$.

Arguments

  • de: Feature distance estimator.
  • Z: Feature matrix assets × features if dims = 1, features × assets when dims = 2. May also be a 3-D array of time-varying features, in which case the observation axis always leads: observations × assets × features if dims = 1, observations × features × assets when dims = 2.
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments (ignored).

Returns

  • S::Matrix{<:Number}: Similarity matrix, assets × assets.
  • D::Matrix{<:Number}: Distance matrix, assets × assets.

Examples

julia> Z = [1.0 0.0; 0.0 1.0; 1.0 1.0];julia> S, D = cor_and_dist(FeatureDistance(), Z);julia> S3×3 Matrix{Float64}: 1.0          6.12323e-17  0.707107 6.12323e-17  1.0          0.707107 0.707107     0.707107     1.0

Related

source
PortfolioOptimisers._as_correlationFunction
_as_correlation(rho::MatNum, sym::Symbol = :rho) -> MatNum

Coerce a square matrix to a correlation matrix, converting it from a covariance matrix when its diagonal says it is one.

The value of the diagonal decides, never the type. A matrix whose diagonal is all ones is already a correlation matrix and is returned as the same object; any other diagonal is read as the variances of a covariance matrix. This is the same test the matrix processing pipeline applies, so the two layers agree on what a correlation matrix is. The square-matrix check runs here, once, for every correlation-based algorithm's matrix entry point.

Algorithm

  1. Check that rho is square, reporting the failure under the name sym.
  2. Read the diagonal of rho into s. LinearAlgebra.diag allocates, so rho is never written to.
  3. When every entry of s is one, return rho itself. Steps 4 and 5 do not run.
  4. Otherwise replace s with its square roots, giving the standard deviations.
  5. Divide rho by the outer product of s with StatsBase.cov2cor, giving a new correlation matrix.

Arguments

  • rho: Correlation matrix assets × assets, or the covariance matrix to convert.
  • sym: Name to report the square-matrix failure under.

Validation

  • rho is square.

Returns

  • rho::MatNum: Correlation matrix assets x assets.

Details

  • The argument is never mutated on either route. Step 2 copies the diagonal, and step 5 builds a new matrix.
  • The conversion round-trips: the correlation of a covariance matrix built from a correlation matrix and a vector of standard deviations is that correlation matrix again.

Related

source
PortfolioOptimisers._absguardFunction
_absguard(rho::MatNum) -> MatNum

Supply the magnitude of rho to the two algorithms that are defined on it, without allocating when the magnitude is already rho.

This is an allocation guard, not a branch in the mathematics. abs.(rho) equals rho entry for entry whenever no entry of rho is negative, so both arms return the same numbers for every input, -0.0 included; the guard only decides whether a second matrix is built. Shared by SimpleAbsoluteDistance and LogDistance.

Algorithm

  1. Test every entry of rho against zero.
  2. When no entry is negative, return rho itself, the same object the caller passed.
  3. Otherwise return abs.(rho), a new matrix.

Arguments

  • rho: Correlation matrix assets × assets.

Returns

  • rho::MatNum: The magnitude of the argument. It is the argument itself when the argument holds no negative entry.

Details

  • The test reads the whole matrix, so one negative entry allocates the copy for all of them. That is the intended reading of the two algorithms, which take the magnitude of every entry.
  • NaN compares false against zero, so a matrix holding one takes the allocating arm. abs(NaN) is NaN, so that entry is NaN on either arm.

Related

source
PortfolioOptimisers._dist_from_corFunction
_dist_from_cor(alg::RhoDistanceAlgorithm, power::Option{<:Integer}, rho::MatNum) -> MatNum

Turn a correlation matrix into a distance matrix, for one of the four correlation-based algorithms.

This is the shared kernel behind the distance and cor_and_dist entry points: they differ only in how they obtain rho, never in the transform they apply to it. Eight methods cover the four algorithms of RhoDistanceAlgorithm at each of the two power cases.

Mathematical definition

Distance states the eight closed forms and the scaling $s$. Each algorithm's own docstring states the base case and the range it is defined on.

Algorithm

power selects the method, so the base case never raises rho to a power.

  1. SimpleAbsoluteDistance and LogDistance replace rho with its magnitude through _absguard. SimpleDistance and CorrelationDistance do not, and read the signed correlation.
  2. When power is an Integer, raise rho to it entry by entry. When power is nothing, leave rho as it is.
  3. SimpleDistance scales $1 - \rho$ by 1//2 for an odd power and by 1//1 for an even one, and by 1//2 in the base case. The other three apply no scaling.
  4. The three square-root algorithms clamp the radicand into $[0,\,1]$ with clamp! and take its square root. LogDistance instead takes $-\log$ and floors the result at zero with max.

Arguments

  • alg: Distance algorithm.
  • power: Optional matrix exponent. nothing and 1 both give the base distance, so only power >= 2 changes the result.
  • rho: Correlation matrix assets × assets.

Returns

  • D::MatNum: Distance matrix assets x assets, in the units the distance algorithm defines.

Details

  • Every method allocates its own result, and clamp! writes only into that allocation. rho is never mutated.
  • The scale of step 3 is a Rational, so the element type of rho is carried through: a Float32 correlation matrix gives a Float32 distance matrix, as it does under the other three algorithms.
  • CanonicalDistance and VariationInfoDistance never reach this kernel. The first is a redirect that resolves to one of the four before the call, and the second reads the data matrix and holds no correlation.

Related

source
PortfolioOptimisers.RhoDistanceAlgorithmType
const RhoDistanceAlgorithm = Union{SimpleDistance, SimpleAbsoluteDistance,
                                   LogDistance, CorrelationDistance}

Union of the correlation-based distance algorithms: those whose distance matrix is a pure function of a correlation matrix via _dist_from_cor. Excludes VariationInfoDistance (information-theoretic, computed from the data matrix) and CanonicalDistance (a redirect that selects one of the others from the covariance estimator).

Related

source
PortfolioOptimisers.assert_dimsFunction
assert_dims(dims::Integer)
assert_dims(
    dims::Integer,
    sym::Union{AbstractString, Symbol}
)

Assert that dims selects a valid matrix dimension (dims in (1, 2)).

Arguments

  • dims: Dimension selector to check.
  • sym: Symbolic name used in the error message.

Returns

  • nothing.

Details

  • Throws DomainError if dims ∉ (1, 2).

Related

source
PortfolioOptimisers.dims_orientedFunction
dims_oriented(
    dims::Integer,
    A::Union{Nothing, AbstractMatrix}
) -> Any

Validate dims and return the matrices with the observations along the rows.

Arguments

  • dims: Dimension along which the observations lie.
  • A, B, Cs...: Matrices to orient. A nothing passes through unchanged, so an optional matrix needs no branch of its own.

Validation

Returns

  • A: The oriented matrix, when one matrix is given.
  • (A, B, Cs...): A tuple of the oriented matrices, when more than one is given.

Details

  • dims == 1 returns the input untouched. dims == 2 returns its transpose.
  • The guard and the orientation are one call, so a caller cannot orient a matrix without validating dims. This is the single decision point: a leaf that spelled the guard and the transpose by hand could omit the guard and answer a dims of 3 with the raw input.

Related

source

References

[4]
D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025).