Regularisation Constraints

PortfolioOptimisers.LpRegularisationType
struct LpRegularisation{__T_p, __T_val} <: AbstractRegularisationEstimator

Lp-norm regularisation term added to the optimisation objective.

Penalises concentrated portfolios by encouraging weight smoothness for $p > 1$.

The same estimator serves double duty. In the lp field of JuMPOptimiser it is a penalty, and val is the coefficient multiplying the norm. In the lpc field it is a constraint, and val is instead an upper bound on the p-norm of the weights. The norm order p means the same thing in both. See set_lp_regularisation! and set_weight_norm_p_constraints!.

Mathematical definition

\[\begin{align} \text{penalty} &= \mathrm{val} \cdot \lVert \boldsymbol{w} \rVert_p\,. \end{align}\]

Where:

  • $\mathrm{val}$: Regularisation coefficient.
  • $p > 1$: Norm order.
  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.

Fields

  • p: Norm order, p > 1.
  • val: Penalty coefficient when the estimator is used as a regularisation term (the lp field of JuMPOptimiser), or the upper bound on the p-norm of the weights when it is used as a norm constraint (the lpc field). As a regularisation term it is the ambiguity radius of a type-$q$ Wasserstein ground metric with $1/p + 1/q = 1$. As a norm constraint it is a ceiling, which is a different quantity. One field therefore carries two readings, so the bound is Num_AmbRadNormCeilCal, which admits both rule families, and each of the two routes refuses the family that has no reading on it. It is the one slot that admits no plain function, because a function names no family and the two routes read the family.

Constructors

LpRegularisation(;    p::Number = 3,    val::Num_AmbRadNormCeilCal = 1e-3) -> LpRegularisation

Keywords correspond to the struct's fields.

Validation

  • isfinite(p).
  • p > 1.
  • If val is a number: val > 0 and finite.
  • The role in val is checked by the field that holds the term, not here. val is the one dual-use slot in the library, so this constructor cannot know which reading applies: JuMPOptimiser's constructor refuses a norm-ceiling role in lp and a radius role in lpc, and the two factory routes refuse the same pairings again.

Related

References

  • [131] V. DeMiguel, L. Garlappi, F. J. Nogales and R. Uppal. A Generalized Approach to Portfolio Optimization: Improving Performance by Constraining Portfolio Norms. Management Science 55, 798–812 (2009).
source
PortfolioOptimisers.L2RegularisationType
struct L2Regularisation{__T_val, __T_alg} <: AbstractRegularisationEstimator

L2-norm regularisation term added to the optimisation objective.

Penalises concentrated portfolios by shrinking the weights towards zero. The alg field selects the formulation used to express the penalty, which determines both the cones the solver sees and the power of the norm being penalised, so val must be interpreted in the light of the chosen formulation — see _set_l2_regularisation!.

Mathematical definition

\[\begin{align} \text{penalty} &= \lambda_2 \lVert \boldsymbol{w} \rVert_2\,, \\ \text{penalty} &= \lambda_2 \lVert \boldsymbol{w} \rVert_2^2\,. \end{align}\]

Where:

  • $\lambda_2$: L2 regularisation coefficient, the val field.
  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.

The first form is used by SOCRiskExpr; the second by SquaredSOCRiskExpr, QuadRiskExpr and RSOCRiskExpr.

Fields

  • alg: Second-moment formulation used to express the L2 penalty.

Constructors

L2Regularisation(;    val::Num_AmbRadCal = 1e-4,    alg::SecondMomentFormulation = SOCRiskExpr()) -> L2Regularisation

Keywords correspond to the struct's fields.

Validation

  • If val is a number: val > 0 and finite.
  • If val holds an ambiguity-radius rule: alg must be SOCRiskExpr.

Related

References

  • [131] V. DeMiguel, L. Garlappi, F. J. Nogales and R. Uppal. A Generalized Approach to Portfolio Optimization: Improving Performance by Constraining Portfolio Norms. Management Science 55, 798–812 (2009).
source
PortfolioOptimisers.factoryFunction
factory(
    x::LpRegularisation,
    pr::AbstractPriorResult
) -> LpRegularisation
factory(
    x::LpRegularisation,
    pr::AbstractPriorResult,
    slv
) -> LpRegularisation

Resolve the ambiguity radius in val against prior result pr, and return an LpRegularisation holding the number.

It carries the reading of factory on L2Regularisation unchanged. The estimator has one norm order and no formulation slot, so no pairing of a rule with a formulation can be wrong and assert_ambiguity_radius_formulation never runs here: val multiplies norm(w, p) and never its square. The role guard below is a different check.

The same estimator also serves as a norm constraint through the lpc field of JuMPOptimiser, where val is an upper bound and not a coefficient. Both routes share one field and one bound, so the route settles the reading: this method refuses a norm-ceiling rule through assert_penalty_coefficient_role, and norm_ceiling_factory refuses a radius rule on the other side.

The slot is named val and its key is :lpreg_val, because L2Regularisation names its own coefficient val too and the two carry two different ground metrics. The two keys are the two names field_dict already uses for the two slots.

The key still names no norm order, because p lives on this estimator and one rule may stand in several terms. So this route states the term's own order in the CalibrationContext it resolves the slot against, on the same terms as norm_ceiling_factory. DualNormRadius is the rule that reads it.

Arguments

  • x: The regularisation term.
  • pr: Prior result the rule reads.
  • slv: Effective solver, or nothing.

Returns

  • LpRegularisation: The term, with val holding a number.

Related

source
PortfolioOptimisers.factoryFunction
factory(
    x::L2Regularisation,
    pr::AbstractPriorResult
) -> L2Regularisation
factory(
    x::L2Regularisation,
    pr::AbstractPriorResult,
    slv
) -> L2Regularisation

Resolve the ambiguity radius in val against prior result pr, and return an L2Regularisation holding the number.

This is the channel JuMPOptimiser uses: the estimator is not @propagatable, so the resolution takes the ordinary factory verb rather than the generated one, and assemble_jump_model! calls it with the optimisation's own prior result and solver. The rebuild goes through the keyword constructor, so the positivity check and assert_ambiguity_radius_formulation both re-run on the calibrated number.

The weights-only factory(l2, w) and port_opt_view carry the estimator through untouched, which is right: neither holds a prior result, so neither can resolve a rule, and a rule that survives a cluster slice is resolved against that cluster's own prior when the model is assembled.

The slot is named val and its key is :l2reg_val, because LpRegularisation names its own coefficient val too and the two carry two different ground metrics. A key that read :val could not tell the type-2 metric of this penalty from the type-$q$ metric of that one, so DualNormRadius would have no reading of either. The two keys are the two names field_dict already uses for the two slots.

Arguments

  • x: The regularisation term.
  • pr: Prior result the rule reads.
  • slv: Effective solver, or nothing.

Returns

  • L2Regularisation: The term, with val holding a number.

Related

source

References

[131]
V. DeMiguel, L. Garlappi, F. J. Nogales and R. Uppal. A Generalized Approach to Portfolio Optimization: Improving Performance by Constraining Portfolio Norms. Management Science 55, 798–812 (2009).