Matrix square root

A square root $\mathbf{L}$ of a covariance matrix $\mathbf{\Sigma}$ satisfies $\mathbf{L} \mathbf{L}^{\intercal} = \mathbf{\Sigma}$. A factor prior states its covariance through such a square root, and a second-order cone reads it. A positive definite matrix has a lower Cholesky factor. A singular or a nearly singular matrix has none, and the algorithms below state what to do then:

  • nothing takes the plain Cholesky factor, and raises a PosDefException.
  • RidgeCholeskySquareRoot adds a small ridge to the diagonal, and grows it until the Cholesky factor exists.
  • EigenFallbackSquareRoot takes the square root of the eigendecomposition of a positive semidefinite matrix, with no ridge.

Each estimator that takes a square root of a covariance holds the algorithm in its field mtx_sqrt: FactorPrior, CrossSectionalFactorPrior, FactorBlackLittermanPrior, Variance, StandardDeviation, DistributionValueatRisk, UncertaintySetVariance, ArithmeticReturn, RelaxedRiskBudgeting, Kurtosis, NegativeSkewness, NormBallUncertaintySetAlgorithm and OrthogonalUncertaintySet. The default of each is EigenFallbackSquareRoot: the plain Cholesky factor of a positive definite matrix, and the square root of the eigendecomposition of a singular positive semidefinite one. RidgeCholeskySquareRoot and nothing, the plain Cholesky factor that refuses a matrix that is not positive definite, are one keyword away.

PortfolioOptimisers.AbstractMatrixSquareRootAlgorithm — Type
abstract type AbstractMatrixSquareRootAlgorithm <: AbstractAlgorithm

Abstract supertype for the algorithms that take a square root of a covariance matrix.

A square root $\mathbf{L}$ of a covariance matrix $\mathbf{\Sigma}$ satisfies $\mathbf{L} \mathbf{L}^{\intercal} = \mathbf{\Sigma}$. Each algorithm states what it does when $\mathbf{\Sigma}$ has no Cholesky factor. nothing in the place of an algorithm takes the plain Cholesky factor, which raises a LinearAlgebra.PosDefException on such a matrix.

Interfaces

In order to implement a new square-root algorithm that works with the library, subtype AbstractMatrixSquareRootAlgorithm with its parameters as fields, and implement the following method:

matrix_square_root

  • matrix_square_root(alg::MyMatrixSquareRootAlgorithm, sigma::MatNum) -> MatNum: The square root of sigma.

Arguments

  • alg: The square-root algorithm.
  • sigma: The covariance matrix, assets × assets.

Returns

  • L::MatNum: A square root with L * L' == sigma, assets × assets.

Examples

julia> struct MyMatrixSquareRootAlgorithm <: PortfolioOptimisers.AbstractMatrixSquareRootAlgorithm endjulia> function PortfolioOptimisers.matrix_square_root(::MyMatrixSquareRootAlgorithm,                                                       sigma::PortfolioOptimisers.MatNum)           return sqrt(sigma)       endjulia> matrix_square_root(MyMatrixSquareRootAlgorithm(), [4.0 0.0; 0.0 9.0])2×2 Matrix{Float64}: 2.0  0.0 0.0  3.0

Related

source
PortfolioOptimisers.RidgeCholeskySquareRoot — Type
struct RidgeCholeskySquareRoot{__T_ridge, __T_tries} <: AbstractMatrixSquareRootAlgorithm

Adds a growing ridge to the diagonal of a covariance matrix until its Cholesky factor exists.

The first try is the plain Cholesky factor of the lower triangle. Where it fails, each later try adds a ridge to the diagonal of the symmetrised matrix, so the square root reproduces the matrix to within the last ridge. A singular matrix, such as the covariance of two factors with one return series, gets a positive definite square root.

Mathematical definition

\[\begin{align} s &= \frac{1}{N} \sum_{i=1}^{N} \lvert \Sigma_{ii} \rvert\,, \\ \lambda_{k} &= 10^{k-1} \max(r s, \epsilon s)\,, \\ \mathbf{L}_{k} \mathbf{L}_{k}^{\intercal} &= \frac{\mathbf{\Sigma} + \mathbf{\Sigma}^{\intercal}}{2} + \lambda_{k} \mathbf{I}\,. \end{align}\]

Where:

  • $s$: Scale of the ridge, the mean absolute variance. Where it is not a finite positive number, $s$ is the largest absolute entry of the symmetrised matrix, and at least one.
  • $N$: Number of rows of $\mathbf{\Sigma}$.
  • $\Sigma_{ii}$: Variance $i$ of the covariance matrix $\mathbf{\Sigma}$.
  • $r$: The relative ridge ridge.
  • $\epsilon$: The machine epsilon of the element type, which keeps the ridge above zero when $r$ is zero.
  • $\lambda_{k}$: Ridge of try $k$, for $k = 1, \ldots,$ tries.
  • $\mathbf{L}_{k}$: Lower Cholesky factor of try $k$.
  • $\mathbf{I}$: Identity matrix.

The ridge is relative to $s$, so the square root of $c^2 \mathbf{\Sigma}$ is $c$ times the square root of $\mathbf{\Sigma}$.

Fields

  • ridge: Ridge of the first try relative to the mean absolute variance, $r$. Each later try multiplies the ridge by ten.
  • tries: Number of tries with a ridge, after the plain Cholesky factor fails.

Constructors

RidgeCholeskySquareRoot(;    ridge::Number = 1e-12,    tries::Integer = 3,) -> RidgeCholeskySquareRoot

Keywords correspond to the struct's fields.

Validation

  • ridge is finite and >= 0.
  • tries > 0.

Examples

julia> RidgeCholeskySquareRoot()RidgeCholeskySquareRoot  ridge ┼ Float64: 1.0e-12  tries ┴ Int64: 3

A matrix of rank one has no Cholesky factor. The first ridge, 1e-12 of the mean variance, makes it positive definite.

julia> sigma = [1.0 1.0; 1.0 1.0];julia> L = matrix_square_root(RidgeCholeskySquareRoot(), sigma);julia> maximum(abs, L * L' - sigma) <= 2e-12true

Related

source
PortfolioOptimisers.EigenFallbackSquareRoot — Type
struct EigenFallbackSquareRoot <: AbstractMatrixSquareRootAlgorithm

Takes the square root of a positive semidefinite covariance matrix from its eigendecomposition where the matrix has no Cholesky factor.

A positive definite matrix gives its lower Cholesky factor. A singular positive semidefinite matrix, such as a covariance of rank one, gives the square root of its eigendecomposition, which reproduces the matrix to rounding and adds no ridge. An indefinite matrix is refused.

Mathematical definition

\[\begin{align} \mathbf{L} &= \begin{cases} \operatorname{chol}(\mathbf{\Sigma}) & \mathbf{\Sigma} \succ 0\,, \\ \mathbf{V} \max(\mathbf{\Lambda}, 0)^{1/2} & \text{otherwise, with } \mathbf{\Sigma} = \mathbf{V} \mathbf{\Lambda} \mathbf{V}^{\intercal}\,. \end{cases} \end{align}\]

Where:

  • $\mathbf{L}$: Square root of $\mathbf{\Sigma}$, with $\mathbf{L} \mathbf{L}^{\intercal} = \mathbf{\Sigma}$.
  • $\operatorname{chol}$: Lower Cholesky factor.
  • $\mathbf{V}$, $\mathbf{\Lambda}$: Eigenvectors, and the diagonal matrix of the eigenvalues. The maximum with zero removes a negative eigenvalue of rounding.

Constructors

EigenFallbackSquareRoot() -> EigenFallbackSquareRoot

Examples

julia> sigma = [1.0 1.0; 1.0 1.0];julia> L = matrix_square_root(EigenFallbackSquareRoot(), sigma);julia> maximum(abs, L * L' - sigma) < 1e-15true

Related

source
PortfolioOptimisers.matrix_square_root — Function
matrix_square_root(::Nothing, sigma::MatNum) -> MatNum
matrix_square_root(alg::RidgeCholeskySquareRoot, sigma::MatNum) -> MatNum
matrix_square_root(alg::EigenFallbackSquareRoot, sigma::MatNum) -> MatNum

Takes a square root $\mathbf{L}$ of a covariance matrix, with $\mathbf{L} \mathbf{L}^{\intercal} = \mathbf{\Sigma}$.

nothing takes the plain lower Cholesky factor. RidgeCholeskySquareRoot takes the Cholesky factor of the matrix with the first ridge that makes it positive definite. EigenFallbackSquareRoot takes the Cholesky factor where it exists, and the square root of the eigendecomposition of a positive semidefinite matrix otherwise. A FactorPrior and a CrossSectionalFactorPrior take the square root of their factor covariance through this function.

Arguments

  • alg: The square-root algorithm, or nothing.
  • sigma: The covariance matrix, assets × assets.

Validation

  • nothing: sigma has a Cholesky factor. Raises a LinearAlgebra.PosDefException.
  • RidgeCholeskySquareRoot: one try of ridge_cholesky succeeds. Raises a LinearAlgebra.PosDefException with the info of the plain factorisation.
  • EigenFallbackSquareRoot: a matrix that has no Cholesky factor is Hermitian, and its smallest eigenvalue is at least $-N \epsilon \max_i \lvert \lambda_i \rvert$. Here $N$ is the number of rows and $\epsilon$ is the machine epsilon of the element type. Raises LinearAlgebra.PosDefException(-1) and LinearAlgebra.PosDefException(1).

Returns

  • L::MatNum: The square root, assets × assets. It is lower triangular except for the eigen square root.

Examples

The three members differ only on a matrix that has no Cholesky factor.

julia> using LinearAlgebrajulia> sigma = [1.0 1.0; 1.0 1.0];julia> try           matrix_square_root(nothing, sigma)       catch err           err isa PosDefException       endtruejulia> L = matrix_square_root(RidgeCholeskySquareRoot(), sigma);julia> maximum(abs, L * L' - sigma - 1e-12I) < 1e-15truejulia> L = matrix_square_root(EigenFallbackSquareRoot(), sigma);julia> maximum(abs, L * L' - sigma) < 1e-15true

Related

source