Skip to content
6

Tools

PorfolioOptimisers.jl is a complex codebase which uses a variety of general purpose tools including functions, constants and types.

Utility functions

We strive to be as type-stable, inferrable, and immutable as possible in order to improve robustness, performance, and correctness. These functions help us achieve these goals.

PortfolioOptimisers.traverse_concrete_subtypes Function
julia
traverse_concrete_subtypes(t, ctarr::Option{<:AbstractVector} = nothing)

Recursively traverse all subtypes of the given abstract type t and collect all concrete struct types into ctarr.

Arguments

  • t: An abstract type whose subtypes will be traversed.

  • ctarr: Optional An array to collect the concrete types. If not provided, a new empty array is created.

Returns

An array containing all concrete struct types that are subtypes (direct or indirect) of types.

Examples

julia
julia> abstract type MyAbstract end

julia> struct MyConcrete1 <: MyAbstract end

julia> struct MyConcrete2 <: MyAbstract end

julia> traverse_concrete_subtypes(MyAbstract)
2-element Vector{Any}:
 MyConcrete1
 MyConcrete2
source
PortfolioOptimisers.concrete_typed_array Function
julia
concrete_typed_array(A::AbstractArray)

Convert an AbstractArray A to a concrete typed array, where each element is of the same type as the elements of A.

This is useful for converting arrays with abstract element types to arrays with concrete element types, which can improve performance in some cases.

Arguments

  • A: The input array.

Returns

A new array with the same shape as A, but with a concrete element type inferred from the elements of A.

Examples

julia
julia> A = Any[1, 2.0, 3];

julia> PortfolioOptimisers.concrete_typed_array(A)
3-element Vector{Union{Float64, Int64}}:
 1
 2.0
 3
source
PortfolioOptimisers.factory Method
julia
factory(::Nothing, args...; kwargs...)

No-op factory function for constructing objects with a uniform interface.

Defining methods which dispatch on the first argument allows for a consistent factory interface across different types.

Arguments

  • ::Nothing: Indicates no object should be constructed.

  • args...: Arbitrary positional arguments (ignored).

  • kwargs...: Arbitrary keyword arguments (ignored).

Returns

  • nothing.

Related

source

Assertions

In order to increase correctness, robustness, and safety, we make extensive use of defensive programming. The following functions perform some of these validations and are usually called at variable instantiation.

PortfolioOptimisers.assert_nonempty_nonneg_finite_val Function
julia
assert_nonempty_nonneg_finite_val(val::AbstractDict, val_sym::Symbol = :val)
assert_nonempty_nonneg_finite_val(val::VecPair, val_sym::Symbol = :val)
assert_nonempty_nonneg_finite_val(val::ArrNum, val_sym::Symbol = :val)
assert_nonempty_nonneg_finite_val(val::Pair, val_sym::Symbol = :val)
assert_nonempty_nonneg_finite_val(val::Number, val_sym::Symbol = :val)
assert_nonempty_nonneg_finite_val(args...)

Validate that the input value is non-empty, non-negative and finite.

Arguments

  • val: Input value to validate.

  • val_sym: Symbolic name used in the error messages.

Returns

  • nothing.

Details

  • val: Input value to validate.
    • ::AbstractDict: !isempty(val), any(isfinite, values(val)), all(x -> x >= 0, values(val)).

    • ::VecPair: !isempty(val), any(isfinite, getindex.(val, 2)), all(x -> x[2] >= 0, val).

    • ::ArrNum: !isempty(val), any(isfinite, val), all(x -> x >= 0, val).

    • ::Pair: isfinite(val[2]) and val[2] >= 0.

    • ::Number: isfinite(val) and val >= 0.

    • args...: Always passes.

Related

source
PortfolioOptimisers.assert_nonempty_gt0_finite_val Function
julia
assert_nonempty_gt0_finite_val(val::AbstractDict, val_sym::Symbol = :val)
assert_nonempty_gt0_finite_val(val::VecPair, val_sym::Symbol = :val)
assert_nonempty_gt0_finite_val(val::ArrNum, val_sym::Symbol = :val)
assert_nonempty_gt0_finite_val(val::Pair, val_sym::Symbol = :val)
assert_nonempty_gt0_finite_val(val::Number, val_sym::Symbol = :val)
assert_nonempty_gt0_finite_val(args...)

Validate that the input value is non-empty, greater than zero, and finite.

Arguments

  • val: Input value to validate.

  • val_sym: Symbolic name used in the error messages.

Returns

  • nothing.

Details

  • val: Input value to validate.
    • ::AbstractDict: !isempty(val), any(isfinite, values(val)), all(x -> x > 0, values(val)).

    • ::VecPair: !isempty(val), any(isfinite, getindex.(val, 2)), all(x -> x[2] > 0, val).

    • ::ArrNum: !isempty(val), any(isfinite, val), all(x -> x > 0, val).

    • ::Pair: isfinite(val[2]) and val[2] > 0.

    • ::Number: isfinite(val) and val > 0.

    • args...: Always passes.

Related

source
PortfolioOptimisers.assert_nonempty_finite_val Function
julia
assert_nonempty_finite_val(val::AbstractDict, val_sym::Symbol = :val)
assert_nonempty_finite_val(val::VecPair, val_sym::Symbol = :val)
assert_nonempty_finite_val(val::ArrNum, val_sym::Symbol = :val)
assert_nonempty_finite_val(val::Pair, val_sym::Symbol = :val)
assert_nonempty_finite_val(val::Number, val_sym::Symbol = :val)
assert_nonempty_finite_val(args...)

Validate that the input value is non-empty and finite.

Arguments

  • val: Input value to validate.

  • val_sym: Symbolic name used in the error messages.

Returns

  • nothing.

Details

  • val: Input value to validate.
    • ::AbstractDict: !isempty(val), any(isfinite, values(val)).

    • ::VecPair: !isempty(val), any(isfinite, getindex.(val, 2)).

    • ::ArrNum: !isempty(val), any(isfinite, val).

    • ::Pair: isfinite(val[2]).

    • ::Number: `isfinite(val).

    • args...: Always passes.

Related

source
PortfolioOptimisers.assert_matrix_issquare Function
julia
assert_matrix_issquare(A::MatNum, A_sym::Symbol = :A)

Assert that the input matrix is square.

Arguments

  • A: Input matrix to validate.

  • A_sym: Symbolic name used in error messages.

Returns

  • nothing.

Validation

  • size(A, 1) == size(A, 2).

Details

  • Throws DimensionMismatch if the check fails.
source

Mathematical functions

PortfolioOptimisers.jl makes use of various mathematical operators, some of which are generic to support the variety of inputs supported by the library.

PortfolioOptimisers.:⊗ Function
julia
(A::ArrNum, B::ArrNum)

Tensor product of two arrays. Returns a matrix of size (length(A), length(B)) where each element is the product of elements from A and B.

Examples

julia
julia> PortfolioOptimisers.:([1, 2], [3, 4])
2×2 Matrix{Int64}:
 3  4
 6  8

Related

source
PortfolioOptimisers.:⊙ Function
julia
(A, B)

Elementwise (Hadamard) multiplication.

Examples

julia
julia> PortfolioOptimisers.:([1, 2], [3, 4])
2-element Vector{Int64}:
 3
 8

julia> PortfolioOptimisers.:([1, 2], 2)
2-element Vector{Int64}:
 2
 4

julia> PortfolioOptimisers.:(2, [3, 4])
2-element Vector{Int64}:
 6
 8

julia> PortfolioOptimisers.:(2, 3)
6
source
PortfolioOptimisers.:⊘ Function
julia
(A, B)

Elementwise (Hadamard) division.

Examples

julia
julia> PortfolioOptimisers.:([4, 9], [2, 3])
2-element Vector{Float64}:
 2.0
 3.0

julia> PortfolioOptimisers.:([4, 6], 2)
2-element Vector{Float64}:
 2.0
 3.0

julia> PortfolioOptimisers.:(8, [2, 4])
2-element Vector{Float64}:
 4.0
 2.0

julia> PortfolioOptimisers.:(8, 2)
4.0
source
PortfolioOptimisers.:⊕ Function
julia
(A, B)

Elementwise (Hadamard) addition.

Examples

julia
julia> PortfolioOptimisers.:([1, 2], [3, 4])
2-element Vector{Int64}:
 4
 6

julia> PortfolioOptimisers.:([1, 2], 2)
2-element Vector{Int64}:
 3
 4

julia> PortfolioOptimisers.:(2, [3, 4])
2-element Vector{Int64}:
 5
 6

julia> PortfolioOptimisers.:(2, 3)
5
source
PortfolioOptimisers.:⊖ Function
julia
(A, B)

Elementwise (Hadamard) subtraction.

Examples

julia
julia> PortfolioOptimisers.:([4, 6], [1, 2])
2-element Vector{Int64}:
 3
 4

julia> PortfolioOptimisers.:([4, 6], 2)
2-element Vector{Int64}:
 2
 4

julia> PortfolioOptimisers.:(8, [2, 4])
2-element Vector{Int64}:
 6
 4

julia> PortfolioOptimisers.:(8, 2)
6
source
PortfolioOptimisers.dot_scalar Function
julia
dot_scalar(a::Union{<:Number, <:AbstractJuMPScalar}, b::VecNum)
dot_scalar(a::VecNum, b::Union{<:Number, <:AbstractJuMPScalar})
dot_scalar(a::VecNum, b::VecNum)

Efficient scalar and vector dot product utility.

  • If one argument is a Union{<:Number, <:AbstractJuMPScalar} and the other an VecNum, returns the scalar times the sum of the vector.

  • If both arguments are VecNums, returns their dot product.

Returns

  • res::Number: The resulting scalar.

Examples

julia
julia> PortfolioOptimisers.dot_scalar(2.0, [1.0, 2.0, 3.0])
12.0

julia> PortfolioOptimisers.dot_scalar([1.0, 2.0, 3.0], 2.0)
12.0

julia> PortfolioOptimisers.dot_scalar([1.0, 2.0, 3.0], [4.0, 5.0, 6.0])
32.0

Related

source

View functions

NestedClustered optimisations need to index the asset universe in order to produce the inner optimisations. These indexing operations are implemented as views, indexing, and custom index generators.

PortfolioOptimisers.nothing_scalar_array_view Function
julia
nothing_scalar_array_view(x::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict}, ::Any)
nothing_scalar_array_view(x::AbstractVector, i)
nothing_scalar_array_view(x::VecScalar, i)
nothing_scalar_array_view(x::AbstractVector{<:Union{<:AbstractVector, <:VecScalar}}, i)
nothing_scalar_array_view(x::AbstractMatrix, i)

Utility for safely viewing into possibly nothing, scalar, or array values.

Arguments

  • x: Input value.

  • i: Index or indices to view.

Returns

  • x: Input value.
    • ::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict}: Returns x unchanged.

    • ::AbstractVector: Returns view(x, i).

    • ::VecScalar: Returns VecScalar(; v = view(x.v, i), s = x.s).

    • ::AbstractVector{<:Union{<:AbstractVector, <:VecScalar}}: Returns a vector of views for each element in x.

    • ::AbstractMatrix: Returns view(x, i, i).

Examples

julia
julia> PortfolioOptimisers.nothing_scalar_array_view(nothing, 1:2)

julia> PortfolioOptimisers.nothing_scalar_array_view(3.0, 1:2)
3.0

julia> PortfolioOptimisers.nothing_scalar_array_view([1.0, 2.0, 3.0], 2:3)
2-element view(::Vector{Float64}, 2:3) with eltype Float64:
 2.0
 3.0

julia> PortfolioOptimisers.nothing_scalar_array_view([[1, 2], [3, 4]], 1)
2-element Vector{SubArray{Int64, 0, Vector{Int64}, Tuple{Int64}, true}}:
 fill(1)
 fill(3)
source
PortfolioOptimisers.nothing_scalar_array_view_odd_order Function
julia
nothing_scalar_array_view_odd_order(x::AbstractMatrix, i, j)

Utility for safely viewing or indexing into possibly nothing or array values with two indices.

  • If x is nothing, returns nothing.

  • Otherwise, returns view(x, i, j).

Arguments

  • x: Input value, which may be nothing or an array.

  • i, j: Indices to view.

Returns

  • The corresponding view or nothing.

Examples

julia
julia> PortfolioOptimisers.nothing_scalar_array_view_odd_order(nothing, 1, 2)

julia> PortfolioOptimisers.nothing_scalar_array_view_odd_order([1 2; 3 4], 1, 2)
0-dimensional view(::Matrix{Int64}, 1, 2) with eltype Int64:
2
source
PortfolioOptimisers.nothing_scalar_array_getindex Function
julia
nothing_scalar_array_getindex(x::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict}, ::Any)
nothing_scalar_array_getindex(x::AbstractVector, i)
nothing_scalar_array_getindex(x::VecScalar, i)
nothing_scalar_array_getindex(x::AbstractVector{<:Union{<:AbstractVector, <:VecScalar}}, i)
nothing_scalar_array_getindex(x::AbstractMatrix, i)

Utility for safely viewing into possibly nothing, scalar, or array values.

Arguments

  • x: Input value.

  • i: Index or indices to view.

Returns

  • x: Input value.
    • ::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict}: Returns x unchanged.

    • ::AbstractVector: Returns view(x, i).

    • ::VecScalar: Returns VecScalar(; v = view(x.v, i), s = x.s).

    • ::AbstractVector{<:Union{<:AbstractVector, <:VecScalar}}: Returns a vector of views for each element in x.

    • ::AbstractMatrix: Returns view(x, i, i).

Examples

julia
julia> PortfolioOptimisers.nothing_scalar_array_getindex(nothing, 1:2)

julia> PortfolioOptimisers.nothing_scalar_array_getindex(3.0, 1:2)
3.0

julia> PortfolioOptimisers.nothing_scalar_array_getindex([1.0, 2.0, 3.0], 2:3)
2-element Vector{Float64}:
 2.0
 3.0

julia> PortfolioOptimisers.nothing_scalar_array_getindex([[1, 2], [3, 4]], 1)
2-element Vector{Int64}:
 1
 3
source
PortfolioOptimisers.nothing_scalar_array_getindex_odd_order Function
julia
nothing_scalar_array_getindex_odd_order(x::AbstractMatrix, i, j)

Utility for safely viewing or indexing into possibly nothing or array values with two indices.

  • If x is nothing, returns nothing.

  • Otherwise, returns view(x, i, j).

Arguments

  • x: Input value, which may be nothing or an array.

  • i, j: Indices to view.

Returns

  • The corresponding view or nothing.

Examples

julia
julia> PortfolioOptimisers.nothing_scalar_array_getindex_odd_order(nothing, 1, 2)

julia> PortfolioOptimisers.nothing_scalar_array_getindex_odd_order([1 2; 3 4], 1, 2)
2
source
PortfolioOptimisers.fourth_moment_index_generator Function
julia
fourth_moment_index_generator(N::Integer, i)

Constructs an index vector for extracting the fourth moment submatrix corresponding to indices i from a covariance matrix of size N × N.

Arguments

  • N: Size of the full covariance matrix.

  • i: Indices of the variables of interest.

Returns

  • idx::Vector{Int}: Indices for extracting the fourth moment submatrix.

Examples

julia
julia> PortfolioOptimisers.fourth_moment_index_generator(3, [1, 2])
4-element Vector{Int64}:
 1
 2
 4
 5
source