Assertions: private API

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_resource_capFunction
assert_resource_cap(val::Integer, cap::Integer, sym::Sym_Str, knob::Sym_Str)

Assert that an untrusted sizing integer val does not exceed the active RESOURCE_LIMITS ceiling cap, failing closed with a DomainError otherwise.

sym names the offending field in the message (e.g. :n_sim) and knob names the ResourceLimits field to raise (e.g. :max_n_sim), so the error tells the caller both what was rejected and how to allow it deliberately.

Arguments

  • val: The requested size.
  • cap: The active ceiling.
  • sym: Symbolic name of the offending field.
  • knob: Symbolic name of the ResourceLimits field that raises the ceiling.

Validation

  • val <= cap, which raises a DomainError naming val, sym, cap and knob.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_ep_grid_sizeFunction
assert_ep_grid_size(K::Integer)

Assert that K, the number of grid points of a grid tail view formulation, is odd, positive and within the active RESOURCE_LIMITS ceiling max_ep_grid.

Every grid point is one binary variable of the mixed-integer program an upper-bound or equality view builds, and one dense row over the posterior probabilities, so K is an untrusted sizing integer of the class assert_resource_cap guards. The parity rule keeps the centre of the grid a point of the grid. Both grid formulations state one rule, so both call this one assertion.

Arguments

  • K: The requested number of grid points.

Validation

  • isodd(K) and 1 <= K <= RESOURCE_LIMITS[].max_ep_grid (every grid point is one binary variable of the mixed-integer program an upper-bound or equality view builds; see RESOURCE_LIMITS).

Returns

  • nothing.

Related

source
PortfolioOptimisers.resolve_rngFunction
resolve_rng(rng::Random.AbstractRNG, seed::Option{<:Integer})

Resolve which random number generator to draw from given an optional seed.

A supplied seed yields a fresh, private generator — a copy of rng reseeded with seed via Random.seed! — so a seeded estimator is reproducible without reseeding, and thereby silently derandomising, the task-global RNG the caller may also own (the default rng is Random.default_rng(), a shared object). When seed is nothing, rng is returned unchanged and used as-is.

Copying rng before seeding (rather than constructing a fixed generator type such as Random.Xoshiro(seed)) preserves both the caller's generator object — it is never mutated — and its type, so a caller-supplied portable generator (e.g. StableRNGs.StableRNG) keeps producing the same stream Random.seed!(rng, seed) did in place. The observable draws are thus identical to the old in-place seeding; only the side effect on the caller's stream disappears.

Arguments

  • rng: Fallback random number generator, used verbatim when seed is nothing.
  • seed: Optional seed. If set, a private Random.seed!(copy(rng), seed) is returned instead of touching rng.

Algorithm

  1. Return rng unchanged when seed is nothing, so the caller's generator is used as it stands.
  2. Otherwise copy rng, reseed the copy with seed, and return the copy. The caller's own generator is never mutated.

Returns

  • Random.AbstractRNG: the generator to draw from.

Related

source
PortfolioOptimisers.assert_nonemptyFunction
assert_nonempty(
    val::Union{AbstractDict, AbstractArray{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, AbstractVector{<:Pair}}
)
assert_nonempty(
    val::Union{AbstractDict, AbstractArray{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, AbstractVector{<:Pair}},
    sym::Union{AbstractString, Symbol}
)

Assert that val is non-empty.

No-op for Pair and Number inputs; emptiness does not apply to scalars.

Arguments

  • val: Container to check; one of AbstractDict, VecPair, or ArrNum.
  • sym: Symbolic name used in the error message.

Validation

Returns

  • nothing.

Related

source
assert_nonempty(::Union{Number, Pair})
assert_nonempty(
    ::Union{Number, Pair},
    ::Union{AbstractString, Symbol}
)

No-op overload of assert_nonempty for scalar inputs.

Emptiness does not apply to Pair or Number values.

Arguments

  • ::Union{<:Pair, <:Number}: Scalar value, not read.
  • ::Sym_Str = :val: Symbolic name, not read.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_finiteFunction
assert_finite(val::AbstractDict)
assert_finite(
    val::AbstractDict,
    sym::Union{AbstractString, Symbol}
)

Assert that every element of val is finite.

Algorithm

The method Julia selects on the type of val is the algorithm. Each method checks one predicate and raises a DomainError that names sym and the predicate it failed.

  1. An AbstractDict checks all(isfinite, values(val)), so the keys are not read.
  2. A VecPair checks all(isfinite, getindex.(val, 2)), so the second element of each pair is the value.
  3. An ArrNum checks all(isfinite, val).
  4. A Pair checks isfinite(val[2]).
  5. A Number checks isfinite(val).

Arguments

  • val: Value to check.
  • sym: Symbolic name used in the error message.

Validation

  • Every element of val is finite, under the predicate that its type selects. A NaN and an infinity both breach it, and a breach raises a DomainError.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_nonnegFunction
assert_nonneg(val::AbstractDict)
assert_nonneg(
    val::AbstractDict,
    sym::Union{AbstractString, Symbol}
)

Assert that all elements of val are non-negative (>= 0).

Algorithm

The method Julia selects on the type of val is the algorithm. Each method checks one predicate and raises a DomainError that names sym and the predicate it failed.

  1. An AbstractDict checks all(x -> 0 <= x, values(val)), so the keys are not read.
  2. A VecPair checks all(x -> 0 <= x[2], val), so the second element of each pair is the value.
  3. An ArrNum checks all(x -> 0 <= x, val).
  4. A Pair checks 0 <= val[2].
  5. A Number checks 0 <= val.

Arguments

  • val: Value to check.
  • sym: Symbolic name used in the error message.

Validation

  • Every element of val is non-negative, under the predicate that its type selects. A breach raises a DomainError.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_gt0Function
assert_gt0(val::AbstractDict)
assert_gt0(
    val::AbstractDict,
    sym::Union{AbstractString, Symbol}
)

Assert that all elements of val are strictly positive (> 0).

Algorithm

The method Julia selects on the type of val is the algorithm. Each method checks one predicate and raises a DomainError that names sym and the predicate it failed.

  1. An AbstractDict checks all(x -> 0 < x, values(val)), so the keys are not read.
  2. A VecPair checks all(x -> 0 < x[2], val), so the second element of each pair is the value.
  3. An ArrNum checks all(x -> 0 < x, val).
  4. A Pair checks 0 < val[2].
  5. A Number checks 0 < val.

Arguments

  • val: Value to check.
  • sym: Symbolic name used in the error message.

Validation

  • Every element of val is strictly positive, under the predicate that its type selects. A breach raises a DomainError.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_nonempty_nonneg_finite_valFunction
assert_nonempty_nonneg_finite_val(
    val::Union{<:AbstractDict, <:VecPair, <:ArrNum, Pair, Number},
    val_sym::Union{Symbol,<:AbstractString} = :val
)
assert_nonempty_nonneg_finite_val(args...)

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

Algorithm

  1. Call assert_nonempty, then assert_finite, then assert_nonneg, each on val and val_sym. The order is the order of the raises, so the first rule a value breaks is the one it is told about.
  2. A value of any other type selects the args... method, which checks nothing. That is what lets a caller validate an optional field without a branch of its own.

Arguments

  • val: Input value to validate.
  • val_sym: Symbolic name used in the error messages.

Validation

Each rule is the one that val's own type selects in the three functions of step 1.

  • ::AbstractDict: !isempty(val), all(isfinite, values(val)), all(x -> x >= 0, values(val)).
  • ::VecPair: !isempty(val), all(isfinite, getindex.(val, 2)), all(x -> x[2] >= 0, val).
  • ::ArrNum: !isempty(val), all(isfinite, val), all(x -> x >= 0, val).
  • ::Pair: isfinite(val[2]) and val[2] >= 0.
  • ::Number: isfinite(val) and val >= 0.
  • Any other type: no rule, so the call always passes.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_nonempty_gt0_finite_valFunction
assert_nonempty_gt0_finite_val(
    val::Union{<:AbstractDict, <:VecPair, <:ArrNum, Pair, Number},
    val_sym::Union{Symbol,<:AbstractString} = :val
)
assert_nonempty_gt0_finite_val(args...)

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

Algorithm

  1. Call assert_nonempty, then assert_finite, then assert_gt0, each on val and val_sym. The order is the order of the raises, so the first rule a value breaks is the one it is told about.
  2. A value of any other type selects the args... method, which checks nothing. That is what lets a caller validate an optional field without a branch of its own.

Arguments

  • val: Input value to validate.
  • val_sym: Symbolic name used in the error messages.

Validation

Each rule is the one that val's own type selects in the three functions of step 1.

  • ::AbstractDict: !isempty(val), all(isfinite, values(val)), all(x -> x > 0, values(val)).
  • ::VecPair: !isempty(val), all(isfinite, getindex.(val, 2)), all(x -> x[2] > 0, val).
  • ::ArrNum: !isempty(val), all(isfinite, val), all(x -> x > 0, val).
  • ::Pair: isfinite(val[2]) and val[2] > 0.
  • ::Number: isfinite(val) and val > 0.
  • Any other type: no rule, so the call always passes.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_nonempty_finite_valFunction
assert_nonempty_finite_val(
    val::Union{<:AbstractDict, <:VecPair, <:ArrNum, Pair, Number},
    val_sym::Union{Symbol,<:AbstractString} = :val
)
assert_nonempty_finite_val(args...)

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

Algorithm

  1. Call assert_nonempty, then assert_finite, each on val and val_sym. The order is the order of the raises, so the first rule a value breaks is the one it is told about.
  2. A value of any other type selects the args... method, which checks nothing. That is what lets a caller validate an optional field without a branch of its own.

Arguments

  • val: Input value to validate.
  • val_sym: Symbolic name used in the error messages.

Validation

Each rule is the one that val's own type selects in the two functions of step 1.

  • ::AbstractDict: !isempty(val), all(isfinite, values(val)).
  • ::VecPair: !isempty(val), all(isfinite, getindex.(val, 2)).
  • ::ArrNum: !isempty(val), all(isfinite, val).
  • ::Pair: isfinite(val[2]).
  • ::Number: isfinite(val).
  • Any other type: no rule, so the call always passes.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_matrix_issquareFunction
assert_matrix_issquare(X::MatNum, X_sym::Symbol = :X)

Assert that the input matrix is square.

Arguments

  • X: Input matrix to validate.
  • X_sym: Symbolic name used in error messages.

Validation

  • size(X, 1) == size(X, 2), which raises a DimensionMismatch naming X_sym and both sizes.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_unit_intervalFunction
assert_unit_interval(val::Number, sym::Union{Symbol,<:AbstractString} = :val)
assert_unit_interval(args...)

Assert that val lies strictly inside the open unit interval (0 < val < 1).

A value of any other type selects the args... method, which checks nothing. That is what lets a caller validate a slot whose bound admits more than a number without a branch of its own, on the terms assert_nonempty_gt0_finite_val already sets. A Calibration Rule (AbstractCalibrationAlgorithm) states no number at construction, so the range is checked when the rebuild runs, against the number the rule returned.

Arguments

  • val: Value to check.
  • sym: Symbolic name used in the error message.

Validation

  • ::Number: 0 < val < 1, which raises a DomainError naming sym and val.
  • Any other type: no rule, so the call always passes.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_closed_unit_intervalFunction
assert_closed_unit_interval(val::Number, sym::Union{Symbol,<:AbstractString} = :val)
assert_closed_unit_interval(args...)

Assert that val lies inside the closed unit interval (0 <= val <= 1).

This is the closed sibling of assert_unit_interval, and the two differ only in whether the ends belong to the interval. A weight that a template may switch off entirely, or hand its full value to, reaches both ends, so it needs this rule and not the open one.

A value of any other type selects the args... method, which checks nothing, on the terms assert_unit_interval already sets.

Arguments

  • val: Value to check.
  • sym: Symbolic name used in the error message.

Validation

  • ::Number: 0 <= val <= 1, which raises a DomainError naming sym and val.
  • Any other type: no rule, so the call always passes.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_all_finiteFunction
assert_all_finite(val::ArrNum, sym::Sym_Str = :val)

Assert that every element of val is finite, failing closed with an IsNonFiniteError otherwise.

assert_finite checks the same predicate and raises a DomainError alongside its assert_nonneg and assert_gt0 siblings; this one raises an IsNonFiniteError and reports where the breach is, so a caller can find the offending entry without the message quoting the data. It guards the comparison-based covariance estimators (GerberCovariance, SmythBrobyCovariance): their X .>= sd / X .<= -sd comparisons silently evaluate a NaN entry as false, masking it as "no co-movement" and yielding a finite, plausible, wrong covariance rather than an error. Clean returns first with an asset selector (e.g. CompleteAssetSelector) or MissingDataFilter — non-finite entries in a returns matrix are a supported input to those, but not to a comparison-based estimator. The message reports the count of offending entries and the first offending index only — never the data values.

Arguments

  • val: Array to check.
  • sym: Symbolic name used in the error message.

Validation

  • all(isfinite, val), which raises an IsNonFiniteError. The message carries the count of offending entries and the first offending index, and never a data value.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_source_selectorFunction
assert_source_selector(src::Symbol)
assert_source_selector(
    src::Symbol,
    sym::Union{AbstractString, Symbol}
)

Assert that a matrix-source selector names one of the two carriers.

Source selectors pick which of the two carriers a matrix is read from: :prior reads the prior result, :data reads the raw returns result. x_src selects the returns matrix X.

Arguments

  • src: Selector to check.
  • sym: Symbolic name used in the error message.

Validation

  • src in (:prior, :data), which raises an ArgumentError naming sym and src.

Returns

  • nothing.

Related

source
PortfolioOptimisers.assert_returns_result_dimsFunction
assert_returns_result_dims(dims::Integer)
assert_returns_result_dims(
    dims::Integer,
    sym::Union{AbstractString, Symbol}
)

Assert that dims names the one layout a ReturnsResult can hold.

A ReturnsResult is always observations × assets, so its asset axis is always 2, whatever dims a caller passes. This assertion refuses dims == 2 instead of flipping the axis, and names prices_to_returns as the way to build a ReturnsResult in a different layout.

Arguments

  • dims: Dimension selector to check.
  • sym: Symbolic name used in the error message.

Validation

  • dims in (1, 2), by assert_dims, which raises a DomainError naming sym and dims.
  • dims == 1, which raises a ConflictingArgumentError naming sym, dims and prices_to_returns.

Returns

  • nothing.

Related

source