Phylogeny Constraints

PortfolioOptimisers.SemiDefinitePhylogenyEstimatorType
struct SemiDefinitePhylogenyEstimator{__T_pl, __T_p} <: AbstractPhylogenyConstraintEstimator

Forbids co-movement between related assets through a semidefinite relaxation, refitting the structure from returns.

The estimator holds the source that builds the relatedness matrix and the penalty factor p. phylogeny_constraints refits the source against a returns matrix and returns a SemiDefinitePhylogeny, which carries the equations this constraint solves.

Which pairs a network source relates — and therefore how strong the constraint is — comes from its AbstractSeparationAlgorithm, not from anything set here. The constraint is weight-inert: A ⊙ W == 0 is the same constraint at any magnitude, so the separation changes the cardinality of the forbidden set and nothing else.

Warning

NetworkEstimator(; sep = PathLength()) relates every reachable pair. A bare PathLength leaves dmax = nothing, which resolves to the observed diameter, so nothing is outside the budget — measured, 190 of 190 pairs — and this estimator then forbids all pairwise co-movement. It is the opposite end of the dial from HopCount's default n = 1. State a numeric dmax to select anything narrower.

Fields

  • pl: Network estimator or clustering estimator. A precomputed PhylogenyResult or Clusters is not accepted: this slot says how to build the phylogeny for whatever universe the estimator is given, and a precomputed one answers for a fixed universe instead. Pass the constraint result if you already have the structure.
  • p: Non-negative penalty factor on the trace of the semidefinite matrix variable. It is read only when the model does not already minimise a variance: a variance objective is itself a trace against that variable, so it pulls the relaxation down on its own and no second term is added.

Constructors

SemiDefinitePhylogenyEstimator(;    pl::NwE_ClE = NetworkEstimator(),    p::Number = 0.05) -> SemiDefinitePhylogenyEstimator

Keywords correspond to the struct's fields. The default p = 0.05 is the value the source's own worked example uses.

Validation

  • p >= 0.
  • pl is bounded by NwE_ClE: a precomputed PhylogenyResult or Clusters is rejected by the type, not by a check, so the keyword constructor raises TypeError rather than deferring the problem to a solve. Build SemiDefinitePhylogeny instead, which is what phylogeny_constraints(estimator, X) returns.

Examples

julia> SemiDefinitePhylogenyEstimator()SemiDefinitePhylogenyEstimator  pl ┼ NetworkEstimator     │    ce ┼ PortfolioOptimisersCovariance     │       │   ce ┼ Covariance     │       │      │    me ┼ SimpleExpectedReturns     │       │      │       │   w ┴ nothing     │       │      │    ce ┼ GeneralCovariance     │       │      │       │   ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true)     │       │      │       │    w ┴ nothing     │       │      │   alg ┴ FullMoment()     │       │   mp ┼ MatrixProcessing     │       │      │     pdm ┼ Posdef     │       │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton     │       │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()     │       │      │      dn ┼ nothing     │       │      │      dt ┼ nothing     │       │      │     alg ┼ nothing     │       │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)     │    de ┼ Distance     │       │   power ┼ nothing     │       │     alg ┴ CanonicalDistance()     │   alg ┼ KruskalTree     │       │     args ┼ Tuple{}: ()     │       │   kwargs ┴ @NamedTuple{}: NamedTuple()     │   sep ┼ HopCount     │       │   n ┴ Int64: 1   p ┴ Float64: 0.05

Related

References

  • [72] D. Cajas. A Graph Theory Approach to Portfolio Optimization. Available at SSRN 4602019 (2023).
  • [73] D. Cajas. A Graph Theory Approach to Portfolio Optimization Part II. Available at SSRN 4667426 (2023).
  • [4] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Sections 13.1.7.2 and 13.2.4.2.
source
PortfolioOptimisers.SemiDefinitePhylogenyType
struct SemiDefinitePhylogeny{__T_A, __T_p} <: AbstractPhylogenyConstraintResult

Drives the product of weights of every related pair of assets to zero through a semidefinite relaxation.

Relatedness is whatever the source that built A calls related: a neighbourhood over a network, or membership of one cluster.

Mathematical definition

The relaxation replaces the outer product of the weights with a symmetric matrix variable and bounds it below through a Schur complement. Where the objective is already a trace against that variable — a variance — the constraint form applies:

\[\begin{align} \underset{\boldsymbol{w},\, \mathbf{W}}{\min}\quad & \mathrm{tr}(\mathbf{\Sigma} \mathbf{W})\\ \textrm{s.t.}\quad & \begin{bmatrix} \mathbf{W} & \boldsymbol{w} \\ \boldsymbol{w}^\intercal & k \end{bmatrix} \succeq 0\,,\\ & \mathbf{A} \odot \mathbf{W} = 0\,,\\ & \mathbf{W} \in \mathbb{S}^{N}\,,\quad \boldsymbol{w} \in \mathcal{W}\,. \end{align}\]

For every other risk measure nothing in the objective pulls the relaxation down, so a penalty term does it instead:

\[\begin{align} \underset{\boldsymbol{w},\, \mathbf{W}}{\min}\quad & \phi(\boldsymbol{w}) + p\, \mathrm{tr}(\mathbf{W})\,. \end{align}\]

Where:

  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
  • $\mathbf{W}$: Symmetric $N \times N$ matrix variable that relaxes $\boldsymbol{w}\boldsymbol{w}^\intercal / k$.
  • $\mathbf{A}$: Relatedness matrix, the A field.
  • $p$: Penalty factor, the p field.
  • $k$: Budget scaling / homogenisation variable.
  • $\mathbf{\Sigma}$: Covariance matrix.
  • $\phi$: Risk measure of the optimiser.
  • $\odot$: Hadamard product.
  • $\mathbb{S}^{N}$: Set of real symmetric $N \times N$ matrices.
  • $\mathcal{W}$: Rest of the feasible set.

The two branches are what the code does: set_sdp_phylogeny_constraints! always writes A ⊙ W == 0 and adds p * tr(W) to the objective penalty only when the model carries no variance. On a 250×6 sample the Hadamard constraint holds to 2.1e-18 under a variance objective and to 3.1e-21 under a conditional-value-at-risk objective.

p therefore sets the size of the relaxation gap, not the strength of the constraint. A ⊙ W == 0 is weight-inert: it is the same constraint at any magnitude of A. What p buys is how closely W tracks the outer product it stands for. On the same sample the largest entry of $\mathbf{W} - \boldsymbol{w}\boldsymbol{w}^\intercal$ is 2.7e-5 under the variance objective, where the objective itself closes the gap, against 0.0274 under conditional value at risk at the default p = 0.05 — three orders of magnitude wider. A wider gap lets a pair of related assets both hold weight while their entry of W absorbs the product.

Fields

  • A: Symmetric relatedness matrix with a zero diagonal. A network source gives the range connection matrix, a clustering source the adjacency label matrix. Stored as given.
  • p: Non-negative penalty factor on the trace of the semidefinite matrix variable. It is read only when the model does not already minimise a variance: a variance objective is itself a trace against that variable, so it pulls the relaxation down on its own and no second term is added.

Constructors

SemiDefinitePhylogeny(    A::MatNum_PhRMatNum,    p::Number) -> SemiDefinitePhylogenySemiDefinitePhylogeny(;    A::MatNum_PhRMatNum,    p::Number = 0.05) -> SemiDefinitePhylogeny

Keywords correspond to the struct's fields. The default p = 0.05 is the value the source's own worked example uses.

Validation

  • LinearAlgebra.issymmetric(A) and all(iszero, LinearAlgebra.diag(A)).
  • p >= 0.

Examples

julia> SemiDefinitePhylogeny([0.0 1.0; 1.0 0.0], 0.05)SemiDefinitePhylogeny  A ┼ 2×2 Matrix{Float64}  p ┴ Float64: 0.05

Related

References

  • [72] D. Cajas. A Graph Theory Approach to Portfolio Optimization. Available at SSRN 4602019 (2023).
  • [73] D. Cajas. A Graph Theory Approach to Portfolio Optimization Part II. Available at SSRN 4667426 (2023).
  • [4] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Sections 13.1.7.2 and 13.2.4.2.
source
PortfolioOptimisers.IntegerPhylogenyEstimatorType
struct IntegerPhylogenyEstimator{__T_pl, __T_B} <: AbstractPhylogenyConstraintEstimator

Caps how many related assets may be held at once, refitting the structure from returns.

The estimator holds the source that builds the relatedness matrix and the cap B. phylogeny_constraints refits the source against a returns matrix and returns an IntegerPhylogeny, which carries the equations this constraint solves.

Which pairs a network source relates comes from its AbstractSeparationAlgorithm, and B is an integer cardinality counted over them. The relatedness itself stays binary under either separation: PhylogenyResult's matrix is Int, and a graded one would not be countable here.

Warning

NetworkEstimator(; sep = PathLength()) relates every reachable pair. A bare PathLength leaves dmax = nothing, which resolves to the observed diameter, so nothing is outside the budget — measured, 190 of 190 pairs. It is the opposite end of the dial from HopCount's default n = 1. State a numeric dmax to select anything narrower.

Fields

  • pl: Network estimator or clustering estimator. A precomputed PhylogenyResult or Clusters is not accepted: this slot says how to build the phylogeny for whatever universe the estimator is given, and a precomputed one answers for a fixed universe instead. Pass the constraint result if you already have the structure.
  • B: Right-hand side of A * z <= B, where z is the held indicator: the largest number of assets that may be held out of each row of A. A scalar applies to every row. A vector states one bound per row, so its length must match the row count of the stored A and not the number of assets. On an estimator the rows do not exist yet, so a vector is only checked against the largest number of clusters the clustering estimator can return.

Constructors

IntegerPhylogenyEstimator(;    pl::NwE_ClE = NetworkEstimator(),    B::Int_VecInt = 1) -> IntegerPhylogenyEstimator

Keywords correspond to the struct's fields.

Validation

Examples

julia> IntegerPhylogenyEstimator()IntegerPhylogenyEstimator  pl ┼ NetworkEstimator     │    ce ┼ PortfolioOptimisersCovariance     │       │   ce ┼ Covariance     │       │      │    me ┼ SimpleExpectedReturns     │       │      │       │   w ┴ nothing     │       │      │    ce ┼ GeneralCovariance     │       │      │       │   ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true)     │       │      │       │    w ┴ nothing     │       │      │   alg ┴ FullMoment()     │       │   mp ┼ MatrixProcessing     │       │      │     pdm ┼ Posdef     │       │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton     │       │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()     │       │      │      dn ┼ nothing     │       │      │      dt ┼ nothing     │       │      │     alg ┼ nothing     │       │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)     │    de ┼ Distance     │       │   power ┼ nothing     │       │     alg ┴ CanonicalDistance()     │   alg ┼ KruskalTree     │       │     args ┼ Tuple{}: ()     │       │   kwargs ┴ @NamedTuple{}: NamedTuple()     │   sep ┼ HopCount     │       │   n ┴ Int64: 1   B ┴ Int64: 1

Related

References

  • [74] F. Ricca and A. Scozzari. Portfolio optimization through a network approach: network assortative mixing and portfolio diversification. European Journal of Operational Research 312, 700–717 (2024).
  • [72] D. Cajas. A Graph Theory Approach to Portfolio Optimization. Available at SSRN 4602019 (2023).
  • [73] D. Cajas. A Graph Theory Approach to Portfolio Optimization Part II. Available at SSRN 4667426 (2023).
  • [4] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Sections 13.1.7.1 and 13.2.4.1.
source
PortfolioOptimisers.IntegerPhylogenyType
struct IntegerPhylogeny{__T_A, __T_B} <: AbstractPhylogenyConstraintResult

Caps at B the number of related assets a mixed-integer model may hold at once.

Relatedness is whatever the source that built A calls related: a neighbourhood over a network, or membership of one cluster.

Mathematical definition

The cap is a mutually exclusive investment constraint on the held binary:

\[\begin{align} \underset{\boldsymbol{w}}{\mathrm{opt}}\quad & \phi(\boldsymbol{w})\\ \textrm{s.t.}\quad & \mathbf{A} \boldsymbol{z} \leq \boldsymbol{B}\,,\\ & \boldsymbol{\ell} \odot \boldsymbol{z} \leq \boldsymbol{w} \leq \boldsymbol{u} \odot \boldsymbol{z}\,,\\ & \boldsymbol{z} \in \{0, 1\}^{N}\,,\quad \boldsymbol{w} \in \mathcal{W}\,. \end{align}\]

Where:

  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
  • $\boldsymbol{z}$: Held binary, one entry per asset.
  • $\mathbf{A}$: Stored relatedness rows, the A field.
  • $\boldsymbol{B}$: Cap, the B field.
  • $\boldsymbol{\ell}$, $\boldsymbol{u}$: Lower and upper weight bounds.
  • $\phi$: Objective function of the optimiser.
  • $\odot$: Hadamard product.
  • $\mathcal{W}$: Rest of the feasible set.

The constructor stores unique(A + I; dims = 1), not the matrix it is given. The identity adds each asset to its own row, and the deduplication drops repeated rows, so one row survives per distinct neighbourhood or cluster. This is why the stored A is usually shorter than it is wide, and why a vector B is checked against the stored row count rather than against the number of assets. A network source with B = 1 then forbids holding two assets that are neighbours; a clustering source with B = 1 holds at most one asset per cluster.

Fields

  • A: Row set of the relatedness matrix, stored as unique(A + I; dims = 1) and not as the matrix passed in. The identity puts each asset in its own row, and the deduplication drops rows that repeat. One row per distinct neighbourhood or cluster survives, which is why the stored matrix is usually shorter than it is wide.
  • B: Right-hand side of A * z <= B, where z is the held indicator: the largest number of assets that may be held out of each row of A. A scalar applies to every row. A vector states one bound per row, so its length must match the row count of the stored A and not the number of assets. On an estimator the rows do not exist yet, so a vector is only checked against the largest number of clusters the clustering estimator can return.

Constructors

IntegerPhylogeny(    A::MatNum_PhRMatNum,    B::Int_VecInt) -> IntegerPhylogenyIntegerPhylogeny(;    A::MatNum_PhRMatNum,    B::Int_VecInt = 1) -> IntegerPhylogeny

Keywords correspond to the struct's fields.

Validation

  • LinearAlgebra.issymmetric(A) and all(iszero, LinearAlgebra.diag(A)).

  • B is validated with assert_nonempty_nonneg_finite_val.

    • AbstractVector: size(unique(A + LinearAlgebra.I; dims = 1), 1) == length(B).

Examples

julia> IntegerPhylogeny(; A = [0.0 1.0; 1.0 0.0], B = 2)IntegerPhylogeny  A ┼ 1×2 Matrix{Float64}  B ┴ Int64: 2

Related

References

  • [74] F. Ricca and A. Scozzari. Portfolio optimization through a network approach: network assortative mixing and portfolio diversification. European Journal of Operational Research 312, 700–717 (2024).
  • [72] D. Cajas. A Graph Theory Approach to Portfolio Optimization. Available at SSRN 4602019 (2023).
  • [73] D. Cajas. A Graph Theory Approach to Portfolio Optimization Part II. Available at SSRN 4667426 (2023).
  • [4] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Sections 13.1.7.1 and 13.2.4.1.
source
PortfolioOptimisers.phylogeny_constraintsFunction
phylogeny_constraints(plc::Option{<:PlCE_PlC}, X::MatNum; dims::Int = 1, kwargs...)
phylogeny_constraints(plcs::VecPlCE_PlC, args...; kwargs...)

Generate phylogeny-based portfolio constraints from an estimator or result.

phylogeny_constraints constructs constraint objects based on phylogenetic, res, or network structures among assets. It supports both semi-definite and integer constraint forms, accepting either an estimator (which wraps a phylogeny or clustering model and penalty parameters) or a precomputed result. If plc is nothing, returns nothing.

If plcs is a vector, this method broadcasts over each element, returning a vector of constraint results.

Arguments

  • plc: A phylogeny constraint estimator, result, or nothing.
  • X: Data matrix (observations × assets) (ignored when plc is not an estimator).
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments passed to the underlying phylogeny matrix routine (ignored when est is not an estimator).

Returns

  • res: Constraint result.

    • SemiDefinitePhylogeny: For semi-definite constraint estimators/results.
    • IntegerPhylogeny: For integer constraint estimators/results.
    • nothing: If est is nothing.

Related

source
phylogeny_constraints(
    plc::AbstractPhylogenyConstraintEstimator,
    pr::Union{AbstractPriorResult, ReturnsResult};
    rd,
    x_src,
    z_src,
    kwargs...
) -> Union{IntegerPhylogeny, SemiDefinitePhylogeny{<:AbstractMatrix{var"#s90"}, <:Number} where var"#s90"<:(Union{var"#s89", var"#s88"} where {var"#s89"<:Number, var"#s88"<:AbstractJuMPScalar})}

Compute phylogeny constraints from asset returns in a prior result using a phylogeny constraint estimator.

phylogeny_constraints delegates to the asset-returns variant by extracting X from pr (or rd if provided and x_src is :data).

Arguments

  • plc: Phylogeny constraint estimator.
  • pr: Prior result or returns result object.
  • rd: Optional returns result (used when x_src = :data or z_src = :data).
  • x_src: If :prior, use asset returns from pr; if :data, use rd. Default is :prior.
  • z_src: Which carrier supplies the feature matrix a FeatureDistance reads: :data takes rd.Z, :prior takes pr.Z. Default is :data. Ignored when no FeatureDistance is in the estimator.
  • kwargs...: Additional keyword arguments passed to the estimator.

Returns

  • Phylogeny constraint result.

Related

source
PortfolioOptimisers.AbstractCentralityConstraintType
abstract type AbstractCentralityConstraint <: AbstractConstraintEstimator

Abstract supertype for all centrality-based constraint types.

All concrete types implementing centrality-based portfolio constraints should be subtypes of AbstractCentralityConstraint.

A subtype states a bound on a linear function of the weights whose coefficients come from a graph, so centrality_constraints reduces it to a LinearConstraint before the model sees it.

Related

source
PortfolioOptimisers.CentralityConstraintType
struct CentralityConstraint{__T_A, __T_B, __T_comp} <: AbstractCentralityConstraint

Bounds the average centrality of the portfolio against a threshold read off the centrality vector itself.

The constraint diversifies by the influence an asset has in the network, rather than by its weight. centrality_constraints turns it into one row of a LinearConstraint.

Mathematical definition

\[\begin{align} \underset{\boldsymbol{w}}{\mathrm{opt}}\quad & \phi(\boldsymbol{w})\\ \textrm{s.t.}\quad & \boldsymbol{c}^\intercal \boldsymbol{w} \mathbin{\square} \bar{c}\,,\\ & \boldsymbol{w} \in \mathcal{W}\,. \end{align}\]

Where:

  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
  • $\boldsymbol{c}$: Centrality vector the estimator in A computes.
  • $\bar{c}$: Threshold, the B field.
  • $\square$: Comparison operator, the comp field.
  • $\phi$: Objective function of the optimiser.
  • $\mathcal{W}$: Rest of the feasible set.

The source states this constraint as an equality against a desired average centrality. comp widens that: == builds an equality row and every other operator an inequality row.

When B is a VectorToScalarMeasure, $\bar{c}$ is that measure of $\boldsymbol{c}$, so the threshold moves with the graph and the constraint always has a feasible point. The measure reads the centrality vector, never the row after comp has flipped its sign: MinValue() gives the smallest entry under <= and under >= alike. On an eight-asset degree vector both give 0.14285714285714285, and MaxValue() gives 0.42857142857142855.

Fields

  • A: Centrality estimator. Its centrality vector is the row of the generated linear constraint.
  • B: Right-hand side of the constraint. A number is the threshold itself. A VectorToScalarMeasure derives the threshold from the centrality vector A produces, so the constraint always has a feasible point.
  • comp: Comparison operator for the centrality constraint. == builds an equality row, every other operator an inequality row.

Constructors

CentralityConstraint(;    A::CentralityEstimator = CentralityEstimator(),    B::Num_VecToScaM = MinValue(),    comp::ComparisonOperator = <=) -> CentralityConstraint

Keywords correspond to the struct's fields.

Examples

julia> CentralityConstraint()CentralityConstraint     A ┼ CentralityEstimator       │   pl ┼ NetworkEstimator       │      │    ce ┼ PortfolioOptimisersCovariance       │      │       │   ce ┼ Covariance       │      │       │      │    me ┼ SimpleExpectedReturns       │      │       │      │       │   w ┴ nothing       │      │       │      │    ce ┼ GeneralCovariance       │      │       │      │       │   ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true)       │      │       │      │       │    w ┴ nothing       │      │       │      │   alg ┴ FullMoment()       │      │       │   mp ┼ MatrixProcessing       │      │       │      │     pdm ┼ Posdef       │      │       │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton       │      │       │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()       │      │       │      │      dn ┼ nothing       │      │       │      │      dt ┼ nothing       │      │       │      │     alg ┼ nothing       │      │       │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)       │      │    de ┼ Distance       │      │       │   power ┼ nothing       │      │       │     alg ┴ CanonicalDistance()       │      │   alg ┼ KruskalTree       │      │       │     args ┼ Tuple{}: ()       │      │       │   kwargs ┴ @NamedTuple{}: NamedTuple()       │      │   sep ┼ HopCount       │      │       │   n ┴ Int64: 1       │   ct ┼ DegreeCentrality       │      │     kind ┼ Int64: 0       │      │   kwargs ┴ @NamedTuple{}: NamedTuple()     B ┼ MinValue()  comp ┴ typeof(<=): <=

Related

References

  • [72] D. Cajas. A Graph Theory Approach to Portfolio Optimization. Available at SSRN 4602019 (2023).
  • [4] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Section 13.1.6.
source
PortfolioOptimisers.centrality_constraintsFunction
centrality_constraints(ccs::CC_VecCC,
                       X::MatNum; dims::Int = 1, kwargs...)

Generate centrality-based linear constraints from one or more CentralityConstraint estimators.

centrality_constraints constructs linear constraints for portfolio optimisation based on asset centrality measures within a phylogeny or network structure. It accepts one or more CentralityConstraint estimators, computes centrality vectors for the given data matrix X, applies the specified reduction measure or threshold, and assembles the resulting constraints into a LinearConstraint object.

Arguments

  • ccs: A single CentralityConstraint or a vector of such estimators.
  • X: Data matrix (observations × assets).
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments passed to the centrality estimator.

Returns

  • lc::Option{<:LinearConstraint}: An object containing the assembled inequality and equality constraints, or nothing if no constraints are present.

Details

  • For each constraint, computes the centrality vector using the estimator in cc.A.
  • Derives the threshold from cc.B. A number is the threshold itself; a VectorToScalarMeasure is applied to the centrality vector.
  • Negates the row and the threshold together for an operator that points the other way, so every inequality is stored in the A w <= B form.
  • Skips a constraint whose centrality vector is empty or all zero.
  • Aggregates constraints into equality and inequality forms.
  • Returns nothing if no valid constraints are generated.

The threshold is derived before the negation, and negated once with the row. Deriving it from the negated row instead negates it a second time, which cancels the flip and turns a MinValue() into a MaxValue() with the wrong sign.

Related

source
centrality_constraints(ccs::Option{<:LinearConstraint}, args...; kwargs...)

No-op fallback for centrality-based constraint propagation.

This method returns the input LinearConstraint object or nothing unchanged. It is used to pass through an already constructed centrality-based constraint object, enabling composability and uniform interface handling in constraint generation workflows.

Arguments

  • ccs: An existing LinearConstraint object or nothing.
  • args...: Additional positional arguments (ignored).
  • kwargs...: Additional keyword arguments (ignored).

Returns

  • ccs::Option{<:LinearConstraint}: The input constraint object or nothing, unchanged.

Related

source
centrality_constraints(
    ccs::Union{CentralityConstraint, AbstractVector{<:CentralityConstraint}},
    pr::Union{AbstractPriorResult, ReturnsResult};
    rd,
    x_src,
    z_src,
    kwargs...
) -> Union{Nothing, LinearConstraint}

Compute centrality constraints from asset returns in a prior result using a centrality constraint estimator.

centrality_constraints delegates to the asset-returns variant by extracting X from pr (or rd if provided and x_src is :data).

Arguments

  • ccs: Centrality constraint estimator or vector thereof.
  • pr: Prior result or returns result object.
  • rd: Optional returns result (used when x_src = :data or z_src = :data).
  • x_src: If :prior, use asset returns from pr; if :data, use rd. Default is :prior.
  • z_src: Which carrier supplies the feature matrix a FeatureDistance reads: :data takes rd.Z, :prior takes pr.Z. Default is :data. Ignored when no FeatureDistance is in the estimator.
  • kwargs...: Additional keyword arguments passed to the estimator.

Returns

  • Centrality constraint result.

Related

source
PortfolioOptimisers._validate_length_integer_phylogeny_constraint_BFunction
_validate_length_integer_phylogeny_constraint_B(alg::Option{<:Integer},
                                                B::VecNum)

Validate that the length of the vector B does not exceed the integer value alg.

This function is used internally to ensure that the number of groups or allocations specified by B does not exceed the allowed maximum defined by alg. If the validation fails, a DomainError is thrown.

Arguments

  • alg:

    • Nothing: No validation is performed.
    • Integer: Specifying the maximum allowed length for B.
  • B: Vector of integers representing group sizes or allocations.

Validation

  • Throws DomainError if length(B) > alg.

Returns

  • nothing.

Details

  • Checks that length(B) <= alg.
  • Used in the construction and validation of integer phylogeny constraints.

Related

source
PortfolioOptimisers.validate_length_integer_phylogeny_constraint_BFunction
validate_length_integer_phylogeny_constraint_B(cle::ClustersEstimator, B::VecNum)
validate_length_integer_phylogeny_constraint_B(args...)

Validate that the length of the vector B does not exceed the maximum allowed by the clustering estimator cle.

Arguments

  • cle: Clustering estimator containing algorithm and maximum group information.
  • B: Vector of integers representing group sizes or allocations.
  • args...: No validation is performed.

Validation

Returns

  • nothing.

Details

  • Checks if cle.onc.max_k is set and validates length(B) accordingly.
  • Delegates to _validate_length_integer_phylogeny_constraint_B for algorithm-specific validation.
  • Used in the construction and validation of integer phylogeny constraints.

Related

source

References

[4]
D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025).
[72]
D. Cajas. A Graph Theory Approach to Portfolio Optimization. Available at SSRN 4602019 (2023).
[73]
D. Cajas. A Graph Theory Approach to Portfolio Optimization Part II. Available at SSRN 4667426 (2023).
[74]
F. Ricca and A. Scozzari. Portfolio optimization through a network approach: network assortative mixing and portfolio diversification. European Journal of Operational Research 312, 700–717 (2024).