The exact projection weight finalisers: private API
PortfolioOptimisers.weights_break_bounds — Function
weights_break_bounds(wb::WeightBounds, w::VecNum) -> BoolTests whether a weight in w lies outside the bounds wb.
An absent bound breaks nothing. A NaN weight lies outside no bound, so this test passes it, and weights_meet_bounds rejects it later.
Mathematical definition
\[\exists\, i : w_{i} < l_{i} \quad \textrm{or} \quad w_{i} > u_{i}\,.\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $\boldsymbol{l}$, $\boldsymbol{u}$: Lower and upper weight bounds. An absent bound is dropped from the programme rather than set to an infinity.
Arguments
wb: The weight bounds. Either bound can benothing.w: The weights to test.
Returns
flag::Bool:trueif a weight lies below its lower bound or above its upper bound.
Related
PortfolioOptimisers.euclidean_weight_projection — Function
euclidean_weight_projection(w::VecNum, wb::WeightBounds) -> VecNumProjects w in the Euclidean norm onto the weights that lie in the bounds wb and sum to sum(w).
EuclideanWeightFinaliser states the programme and its minimiser. This function finds the shift of that minimiser exactly from the kinks of the budget, with no solver and no tolerance.
Algorithm
- Read the budget
sassum(w). - Read the bounds
lbandub. An absent bound is the infinity of the type that a division of two weights returns, so it adds no kink. - Collect the kinks
w .- ubandw .- lb. At a kink, one weight reaches one of its bounds. Between two neighbouring kinks, the sum ofclamp.(w .- theta, lb, ub)is linear inthetaand does not increase. - Find the shift
thetaat which that sum equalss, withbreakpoint_rootover the kinks. - Return
clamp.(w .- theta, lb, ub).
Arguments
w: The weights to project.wb: The weight bounds. Either bound can benothing.
Returns
w::VecNum: The projected weights, a new vector. IfΣ lb > sum(w)orΣ ub < sum(w), no projection exists.breakpoint_rootthen finds the root on the flat tail past the last kink, and the returned weights lie on their bounds with a different sum.
Related
PortfolioOptimisers.entropic_weight_projection — Function
entropic_weight_projection(w::VecNum, wb::WeightBounds) -> VecNumProjects w in relative entropy onto the weights that lie in the bounds wb and sum to sum(w), or returns the Euclidean projection where the entropic one is not defined.
EntropicWeightFinaliser states the programme, its minimiser and its domain. This function finds the scale of that minimiser exactly from the kinks of the budget, with no solver and no tolerance.
Algorithm
- Read the budget
sassum(w). - Spread the bounds over the assets as
lbandub. An absent lower bound is zero, which changes no clip of a non-negative weight. An absent upper bound is the infinity of the type that a division of two weights returns. - When the entropic projection is not defined, return the projection from
euclidean_weight_projection. The projection is not defined when a weight or a lower bound is negative, or whensis not positive. It is also not defined whensis at mostsum(lb), or above the sum ofubover the positive weights andlbover the zero weights. Ats = sum(lb), the only feasible vector islb, and the Euclidean projection returns it. - Collect the kinks
lb ./ wandub ./ w. At a kink, one weight reaches one of its bounds. Between two neighbouring kinks, the sum ofclamp.(t .* w, lb, ub)is linear in the scaletand does not decrease. - Find the scale
tat which that sum equalss, withbreakpoint_rootover the negated kinks.breakpoint_rootneeds a sum that does not increase, so it searches in-t. - Return
clamp.(t .* w, lb, ub).
Arguments
w: The weights to project.wb: The weight bounds. Either bound can benothing.
Returns
w::VecNum: The projected weights, a new vector.
Related
PortfolioOptimisers.weights_bound_tolerance — Function
weights_bound_tolerance(::Type{T}) -> TReturn the tolerance to which weights_meet_bounds holds the finalised weights of element type T to their bounds and to their budget.
A floating-point type rounds, so a finaliser that lands on a bound or on the budget can miss it by a few units in the last place. The tolerance is then $\sqrt{\epsilon}$, with $\epsilon$ the machine epsilon of T. A Rational type does not round, so a finaliser lands on a bound exactly, and the tolerance is zero. Rational has no eps method, so the choice cannot come from eps itself.
The choice is made by dispatch on Type{T}. A package that defines another exact number type adds a method for it.
Algorithm
Tis a subtype ofRational: returnzero(T).Tis any other type: returnsqrt(eps(T)). This covers every floating-point type, and every number type that defineseps, such as an automatic-differentiation dual.
Arguments
T: The element type of the weights. AnIntegertype has no fractional weight to compare, so the caller repairs it withfloat_if_integerfirst.
Returns
tol::T: The tolerance, a non-negative value of typeT.
Examples
julia> PortfolioOptimisers.weights_bound_tolerance(Float64)1.4901161193847656e-8julia> PortfolioOptimisers.weights_bound_tolerance(Rational{Int})0//1Related
PortfolioOptimisers.weights_meet_bounds — Function
weights_meet_bounds(wb::WeightBounds, w::VecNum, s::Number) -> BoolTests whether the finalised weights w are finite, lie in the bounds wb, and sum to the budget s. The last two conditions hold to a tolerance.
finalise_weight_bounds reads it to choose its return code.
Mathematical definition
Every $w_{i}$ is finite, and:
\[\begin{align} \boldsymbol{l} - \tau &\leq \boldsymbol{w} \leq \boldsymbol{u} + \tau\,, \\ \left\lvert \boldsymbol{1}^\intercal \boldsymbol{w} - s \right\rvert &\leq \tau \max\left(1, \lvert s \rvert\right)\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $\boldsymbol{l}$, $\boldsymbol{u}$: Lower and upper weight bounds. An absent bound is dropped from the programme rather than set to an infinity.
- $s$: The budget of the weights before the finaliser moved them.
- $\tau$: The tolerance that
weights_bound_tolerancegives for the element type of $\boldsymbol{w}$, which is $\sqrt{\epsilon}$ for a floating-point type and zero for an exact type such asRational.
The tolerance on the bounds is absolute. The tolerance on the budget is relative when $\lvert s \rvert > 1$.
Arguments
wb: The weight bounds. Either bound can benothing.w: The finalised weights.s: The budget of the weights before the finaliser moved them.
Returns
flag::Bool:trueif the weights meet all three conditions.
Related