MIP Constraints
PortfolioOptimisers.get_mip_ss Function
get_mip_ss(ss::Number, args...) -> NumberReturn the big-M style scaling constant used by MIP constraints.
When ss is a number it is returned directly. When nothing, the value is derived from the largest finite bound magnitude in wb multiplied by 1000, defaulting to 1000.0 when all bounds are infinite or absent.
Arguments
ss::Number: Scaling constant. Returned as-is.
Returns
ss::Number: The scaling constant.
Related
sourcePortfolioOptimisers.set_mip_ss_expr! Function
set_mip_ss_expr!(
model::Model,
ss::Union{Nothing, Number},
wb::WeightBounds
) -> AnyRegister the big-M scaling constant as the model expression :ss and return it.
Asset-space and sub-group MIP builders share the single :ss key; the first caller registers it via get_mip_ss, subsequent callers reuse the registered expression.
Arguments
model::JuMP.Model: The JuMP optimisation model.ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).wb::WeightBounds: Weight bound specification containing lower and upper bounds.
Returns
ss: The registered scaling-constant expression.
Related
sourcePortfolioOptimisers.AbstractMIPSpace Type
abstract type AbstractMIPSpaceAbstract supertype for the weight space a MIP constraint builder acts on.
A MIP space tells the shared builders which expression the binary indicators gate (mip_wx!), how weight bounds map into that space (mip_bounds), and how model keys are named (mip_key).
Related
sourcePortfolioOptimisers.AssetMIPSpace Type
struct AssetMIPSpace <: AbstractMIPSpaceAsset-space MIP constraints: indicators gate the portfolio weights w directly and model keys use the bare names (:ib, :i_mip, :w_mip_lt, ...).
Related
sourcePortfolioOptimisers.SubsetMIPSpace Type
struct SubsetMIPSpace{T1<:(AbstractMatrix{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}}), T2<:Integer} <: AbstractMIPSpaceSub-group MIP constraints: indicators gate the sub-group weights smtx * w and weight bounds map through the selection matrix. Model keys are namespaced as Symbol(pfx, name, :_, i) so multiple sub-groups (and the cardinality/group-cardinality variants) do not collide.
Fields
smtx: Selection matrix mapping assets to sub-groups.pfx::Symbol: Key prefix;:sfor cardinality sub-groups,:sgfor group-cardinality sub-groups.i::Integer: Index of the selection matrix, used in key naming.
Related
sourcePortfolioOptimisers.mip_key Function
mip_key(_::AssetMIPSpace, name::Symbol) -> SymbolMap a logical MIP builder name to the model key for the given space.
Asset space returns the name unchanged; sub-group space returns Symbol(pfx, name, :_, i).
Related
sourcePortfolioOptimisers.mip_wx! Function
mip_wx!(model::Model, _::AssetMIPSpace) -> AnyReturn the weight expression the MIP indicators gate.
Asset space returns the portfolio weights w; sub-group space registers and returns the sub-group weight expression smtx * w under the space's :mtx_expr key.
Related
sourcePortfolioOptimisers.mip_bounds Function
mip_bounds(
_::AssetMIPSpace,
b::AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}}
) -> AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}}Map a weight bound vector into the MIP space.
Asset space returns the bounds unchanged; sub-group space maps them through the selection matrix, smtx * b.
Related
sourcePortfolioOptimisers.use_direct_mip_indicators Function
use_direct_mip_indicators(
model::Model,
_::AssetMIPSpace,
k
) -> BoolWhether the binary indicators can gate the weights directly, without the continuous big-M relaxation of indicator * k.
True when the budget k is a constant. The asset space additionally accepts a unit budget (is_unit_budget): the head has normalised the scale, so the indicators may gate the weights directly even though k is still a free variable.
Related
sourcePortfolioOptimisers.AbstractMIPIndicators Type
abstract type AbstractMIPIndicatorsAbstract supertype for a declared set of MIP binary indicators.
A MIP space (AbstractMIPSpace) says which weights the indicators gate; an indicator bundle says which bits exist and what they mean. The two are independent axes: the declaration step picks the bundle from the features the model needs, and every emitter is written once against the bundle's accessors rather than reading binaries back out of the model by key.
The bits divide into two kinds, and conflating them is a bug — a held bit says an asset is in the portfolio (what cardinality counts), a sign bit says which side it is on. Bundles differ in which of the two they carry:
| bundle | binaries | states |
|---|---|---|
HeldIndicators | ib | held / not |
LongShortIndicators | ilb,isb | long / short / inactive |
SignIndicators | xb | long / short |
Related
sourcePortfolioOptimisers.HeldIndicators Type
struct HeldIndicators{T1, T2} <: AbstractMIPIndicatorsLong-only indicators: one held bit per asset, and no sign.
Fields
ib: Binary held bit.i_mip: Held gate —ibitself, or its continuous relaxationibfwhen the budget is free.
Related
sourcePortfolioOptimisers.LongShortIndicators Type
struct LongShortIndicators{T1, T2, T3, T4, T5} <: AbstractMIPIndicatorsLong-short indicators: a long bit and a short bit per asset, mutually exclusive, so an asset is long, short, or inactive. Carries both a sign (which of ilb/isb) and a held indicator (i_mip = ilb + isb), which is why this bundle can serve cardinality and exact budgets at once.
Fields
ilb,isb: Binary long and short bits.il,is: Long and short gates — the bits themselves, or their continuous relaxationsilf/isfwhen the budget is free.i_mip: Held gate,ilb + isb.
Related
sourcePortfolioOptimisers.SignIndicators Type
struct SignIndicators{T1} <: AbstractMIPIndicatorsSign-only indicators: one sign bit per asset and no held indicator, for when nothing in the model needs to know whether an asset is held.
The sign split is total — w_i = 0 satisfies both w_i >= 0 and w_i <= 0 and is picked up by either branch — so one bit per asset suffices and the inactive state of LongShortIndicators is pure redundancy. This is what lets a model that only pins the decomposition use N binaries rather than 2N.
Fields
xb: Binary sign bit;1selectsw_i >= 0,0selectsw_i <= 0.
Related
sourcePortfolioOptimisers.held Function
held(ind::HeldIndicators) -> AnyReturn the held indicator — the per-asset quantity that is 1 when the asset is in the portfolio. This is what cardinality counts and what integer phylogeny gates on.
SignIndicators deliberately has no method: it carries no held bit, and the declaration step only chooses it when nothing in the model consumes one. A caller that would need a held indicator therefore fails at the seam with a MethodError, rather than reading a sign bit and silently miscounting.
Related
sourcePortfolioOptimisers.held_bin Function
held_bin(ind::HeldIndicators) -> AnyReturn the held binary — the 0/1 per-asset quantity that cardinality sums, group cardinality gates, and integer phylogeny multiplies.
Unlike held, which returns the held gate (i_mip, the continuous relaxation ibf when the budget is free), this is always the raw binary: ib for the long-only bundle, ilb + isb for the long-short one. Counting must key on a bit that is exactly 0 or 1 even when the budget is free and the gate relaxes — the same reason long_bin exists alongside long_gate.
SignIndicators deliberately has no method, for the same reason held does not: it carries no held bit, so a caller that would count one fails at the seam with a MethodError rather than miscounting a sign bit.
Related
sourcePortfolioOptimisers.set_mip_indicators! Function
set_mip_indicators!(model::JuMP.Model, ind::AbstractMIPIndicators)Register the asset-space MIP indicator bundle as the Model-State entry :mip_indicators.
This is what lets a late emitter — integer phylogeny, applied after the fact in assemble_jump_model! — reach the held indicator through mip_indicators and the typed accessors (held_bin) rather than having it hand-threaded back as a return value. With the bundle in Model State, the per-builder raw keys (:ib, :ilb/:isb, ...) stay private to the bundle: nothing outside a builder reaches an indicator by key.
Only the asset space registers a bundle. Sub-group builders consume theirs immediately, in the same call, and never cross the late seam.
Related
sourcePortfolioOptimisers.mip_indicators Function
mip_indicators(model::JuMP.Model)Return the registered asset-space MIP indicator bundle, or nothing when no MIP builder ran.
nothing means the model has no MIP features, so there is no held indicator for a late emitter to gate on.
Related
sourcePortfolioOptimisers.lb_gate Function
lb_gate(ind::HeldIndicators) -> AnyReturn the gate gating the lower weight bound in mip_wb.
The long-only bundle gates it with the held indicator (w = 0 unless held); the long-short bundle gates it with the short gate. See ub_gate for the upper bound.
Related
sourcePortfolioOptimisers.ub_gate Function
ub_gate(ind::HeldIndicators) -> AnyReturn the gate gating the upper weight bound in mip_wb.
The long-only bundle gates it with the held indicator (w = 0 unless held); the long-short bundle gates it with the long gate. See lb_gate for the lower bound.
Related
sourcePortfolioOptimisers.long_gate Function
long_gate(ind::HeldIndicators) -> AnyReturn the gates and binaries the exact-decomposition constraints key on.
long_gate/short_gate bound lw/sw and may be continuous relaxations; long_bin/short_bin are always the binaries themselves, because the slack-closing constraints must key on a bit that is exactly 0 or 1 even when the budget is free and the gates relax.
For HeldIndicators the held bit doubles as the sign: this bundle is only asked for a decomposition under a long-only weight bound, where held and long coincide.
Related
sourcePortfolioOptimisers.short_gate Function
short_gate(ind::HeldIndicators) -> AnyReturn the short-side gate bounding sw in the exact-decomposition constraints — the short counterpart of long_gate, which carries the full explanation.
Related
sourcePortfolioOptimisers.long_bin Function
long_bin(ind::HeldIndicators) -> AnyReturn the long binary the slack-closing exact-decomposition constraints key on — always the bit itself, never a continuous relaxation (see long_gate for why the binaries and gates differ).
Related
sourcePortfolioOptimisers.short_bin Function
short_bin(ind::HeldIndicators) -> AnyReturn the short binary the slack-closing exact-decomposition constraints key on — always the bit itself, never a continuous relaxation (see long_gate for why the binaries and gates differ).
Related
sourcePortfolioOptimisers.mip_wb Function
mip_wb(_::Model, _::AbstractMIPSpace, _::Nothing, args...)Add MIP-compatible weight bound constraints using binary selection variables.
The fall-through method does nothing when wb is nothing. The concrete method adds wx ≥ is ⊙ lb and wx ≤ il ⊙ ub constraints when the respective finite bounds are present, where wx and the bounds live in the space selected by sp (mip_wx!, mip_bounds).
Mathematical definition
Where:
: Portfolio weights vector . , : Long and short binary indicator vectors. , : Lower and upper bound vectors from wb, mapped into the space ofsp.
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the constraints act on.wb::WeightBounds: Weight bound specification containing lower and upper bounds.wx::VecNum: Weight expression frommip_wx!.il: Long binary (or continuous relaxation) indicator variable.is: Short binary (or continuous relaxation) indicator variable.
Returns
nothing.
Related
sourcePortfolioOptimisers.declare_held_indicators! Function
declare_held_indicators!(
model::Model,
sp::AbstractMIPSpace,
wb::Union{Nothing, WeightBounds},
wx::AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}},
ss::Union{Nothing, Number}
) -> HeldIndicatorsDeclare the long-only held indicators and the constraints that give them meaning.
Creates one binary per asset and, when the budget k is a free variable, the continuous relaxation ibf = ib * k with its big-M linking constraints. Applies mip_wb, which is what forces w = 0 for an unheld asset and so makes the bit mean held.
Emits no feature constraints — thresholds, fees, cardinality, phylogeny, and budgets are the business of their own emitters, which take the returned bundle.
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the indicators act on.wb::WeightBounds: Weight bound specification containing lower and upper bounds.wx::VecNum: Weight expression frommip_wx!.ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).
Returns
ind::HeldIndicators: The declared indicator bundle.
Related
sourcePortfolioOptimisers.declare_long_short_indicators! Function
declare_long_short_indicators!(
model::Model,
sp::AbstractMIPSpace,
wb::Union{Nothing, WeightBounds},
wx::AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}},
ss::Union{Nothing, Number}
) -> LongShortIndicators{T1, T2, T3, T4} where {T1<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T2<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T3<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T4<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}}Declare the long-short indicators and the constraints that give them meaning.
Creates a long and a short binary per asset, forces them mutually exclusive (ilb + isb <= 1, so an asset is long, short, or inactive), builds the continuous relaxations ilf/isf with their big-M linking constraints when the budget is free, and applies mip_wb.
Emits no feature constraints; see declare_held_indicators!.
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the indicators act on.wb::WeightBounds: Weight bound specification containing lower and upper bounds.wx::VecNum: Weight expression frommip_wx!.ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).
Returns
ind::LongShortIndicators: The declared indicator bundle.
Related
sourcePortfolioOptimisers.declare_sign_indicators! Function
declare_sign_indicators!(
model::Model,
sp::AbstractMIPSpace,
wb::Union{Nothing, WeightBounds},
wx::AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}},
ss::Union{Nothing, Number}
) -> Union{SignIndicators{Vector{VariableRef}}, SignIndicators{T1} where T1<:(JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}})}Declare a single sign binary per asset.
Unlike the held and long-short declarations there is no mip_wb here and no held indicator: a sign bit needs no weight-bound gating to mean what it means, and this bundle is only chosen when nothing in the model consumes a held indicator.
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the indicators act on.wb::WeightBounds: Weight bound specification containing lower and upper bounds.wx::VecNum: Weight expression frommip_wx!.ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).
Returns
ind::SignIndicators: The declared indicator bundle.
Related
sourcePortfolioOptimisers.short_mip_threshold_constraints Function
short_mip_threshold_constraints(
model::Model,
sp::AbstractMIPSpace,
wb::WeightBounds,
lt::Union{Nothing, Threshold},
st::Union{Nothing, Threshold},
ffl::Union{Nothing, Number, AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}}},
ffs::Union{Nothing, Number, AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}}},
ss::Union{Nothing, Number},
lt_flag::Bool,
st_flag::Bool,
ffl_flag::Bool,
ffs_flag::Bool
) -> LongShortIndicators{T1, T2, T3, T4} where {T1<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T2<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T3<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T4<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}}
short_mip_threshold_constraints(
model::Model,
sp::AbstractMIPSpace,
wb::WeightBounds,
lt::Union{Nothing, Threshold},
st::Union{Nothing, Threshold},
ffl::Union{Nothing, Number, AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}}},
ffs::Union{Nothing, Number, AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}}},
ss::Union{Nothing, Number},
lt_flag::Bool,
st_flag::Bool,
ffl_flag::Bool,
ffs_flag::Bool,
xbgt_flag::Bool
) -> LongShortIndicators{T1, T2, T3, T4} where {T1<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T2<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T3<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T4<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}}Add MIP binary selection variables and threshold constraints for long-short portfolios.
Creates long/short binary indicator variables (or their continuous relaxations when k is a JuMP variable), enforces that each position is either long or short but not both, and applies long/short minimum-holding threshold, fixed-fee, and rebalancing constraints based on the flags provided. The weight expression, bound mapping, and model key naming are selected by sp, so the same builder serves asset-space and sub-group constraints.
Mathematical definition
Mutual-exclusivity and big-M linearisation:
Where:
, : Long and short binary indicator variables for position . , : Continuous relaxations of and . : Budget scaling / homogenisation variable.
Minimum-holding thresholds:
Where:
: Weight expression for position in the space of sp., : Long and short continuous indicator expressions. , : Long and short binary indicator variables for position . , : Long and short minimum-holding thresholds for position . : Big-M constant.
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the constraints act on.wb::WeightBounds: Weight bound specification containing lower and upper bounds.lt::Option{<:Threshold}: Long-side minimum-holding threshold.st::Option{<:Threshold}: Short-side minimum-holding threshold.ffl::Option{<:Num_VecNum}: Long-side fixed fee rate(s).ffs::Option{<:Num_VecNum}: Short-side fixed fee rate(s).ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).lt_flag::Bool: Whether to apply the long-side threshold.st_flag::Bool: Whether to apply the short-side threshold.ffl_flag::Bool: Whether to add long fixed fee expressions. Emitted byset_fixed_fees!againstilb.ffs_flag::Bool: Whether to add short fixed fee expressions. Emitted byset_fixed_fees!againstisb.xbgt_flag::Bool: Whether to pin the long/short decomposition, so the budgets built onlw/swhold exactly (seeset_exact_budget_constraints!). Served byset_exact_budget_constraints!, which reuses this builder'silb/isbrather than introducing a sign indicator of its own — they already mean long and short here, andi_mip = ilb + isbremains the held indicator that cardinality counts.
Returns
ind::LongShortIndicators: The declared indicator bundle.
Related
PortfolioOptimisers.mip_constraints Function
mip_constraints(
model::Model,
sp::AbstractMIPSpace,
wb::WeightBounds,
ffl::Union{Nothing, Number, AbstractVector{<:Union{var"#s34", var"#s33"} where {var"#s34"<:Number, var"#s33"<:AbstractJuMPScalar}}},
lt::Union{Nothing, Threshold},
ss::Union{Nothing, Number},
lt_flag::Bool,
ffl_flag::Bool,
xbgt_flag::Bool
) -> HeldIndicatorsAdd a long-only MIP binary indicator variable and associated constraints to the JuMP optimisation model.
Creates a binary variable per position indicating whether it is held. When k is a JuMP variable, introduces a continuous relaxation with big-M linking constraints. Optionally applies minimum-holding threshold, fixed-fee, and rebalancing constraints. The weight expression, bound mapping, and model key naming are selected by sp, so the same builder serves asset-space and sub-group constraints.
Mathematical definition
Big-M linearisation of
Where:
: Binary inclusion indicator for position . : Continuous relaxation of . : Budget scaling / homogenisation variable. : Big-M constant.
Minimum-holding threshold and cardinality:
Where:
: Weight expression for position in the space of sp.: Continuous relaxation of . : Minimum-holding threshold for position . : Maximum number of non-zero positions (cardinality bound).
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the constraints act on.wb::WeightBounds: Weight bound specification containing lower and upper bounds.ffl::Option{<:Num_VecNum}: Long-side fixed fee rate(s).lt::Option{<:Threshold}: Long-side minimum-holding threshold.ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).lt_flag::Bool: Whether to apply the long-side threshold.ffl_flag::Bool: Whether to add fixed fee expressions. Emitted byset_fixed_fees!againstib.xbgt_flag::Bool: Whether to pin the long/short decomposition, so the budgets built onlw/swhold exactly (seeset_exact_budget_constraints!). Under a long-only weight bound the held bit doubles as the sign, so this builder'sibcan serve it.
Returns
ind::HeldIndicators: The declared indicator bundle.
Related
PortfolioOptimisers.sign_mip_constraints Function
sign_mip_constraints(
model::Model,
sp::AbstractMIPSpace,
wb::WeightBounds,
ss::Union{Nothing, Number}
) -> Union{SignIndicators{Vector{VariableRef}}, SignIndicators{T1} where T1<:(JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}})}Pin the long/short decomposition using a single binary sign indicator per asset.
This is the lean alternative to running a whole long-short builder just to get a sign, for when nothing else in the model needs binaries. It produces N of them rather than 2N.
The long-short builder splits each asset three ways — long, short, or inactive — because a threshold has to tell w_i = 0 apart from w_i >= lt_i, and cardinality has to count the assets that are held. Pinning the decomposition needs neither: the sign split is total, since w_i = 0 satisfies both w_i >= 0 and w_i <= 0 and is picked up by either branch. One bit per asset therefore suffices, and the inactive state is pure redundancy.
It declares the sign bit and hands it to set_exact_budget_constraints!, which emits the constraints; see there for the mathematical definition.
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the constraints act on.wb::WeightBounds: Weight bound specification containing lower and upper bounds.ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).
Returns
ind::SignIndicators: The declared indicator bundle. It carries no held indicator —held_binhas no method for it — because this builder runs only when nothing would consume one.
Related
sourcePortfolioOptimisers.run_mip_builder! Function
run_mip_builder!(
model::Model,
sp::AbstractMIPSpace,
wb::WeightBounds,
lt::Union{Nothing, Threshold},
st::Union{Nothing, Threshold},
ss::Union{Nothing, Number},
lt_flag::Bool,
st_flag::Bool;
ffl,
ffs,
ffl_flag,
ffs_flag,
xbgt_flag,
pin_flag,
sign_only
) -> Union{HeldIndicators, LongShortIndicators{T1, T2, T3, T4} where {T1<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T2<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T3<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}, T4<:Union{JuMP.Containers.DenseAxisArray{_A, _B, Ax, _C} where {_A, _B, Ax<:Tuple, _C<:NTuple{_B, JuMP.Containers._AxisLookup}}, Vector{VariableRef}}}, SignIndicators}Run the MIP indicator builder the requested features call for and return its indicator bundle.
Selects among the three builders on flags shared by the asset space and every sub-group:
sign_mip_constraintswhensign_only— an explicitxbgtwith nothing else to consume a held indicator, so a single sign bit per asset suffices (returns aSignIndicators, which has no held indicator).short_mip_threshold_constraintswhen a short side exists (shared_get(model, :sw)) and something needs it — a short threshold, a fixed fee, or a pinned decomposition.mip_constraintsotherwise — the long-only held builder.
The asset caller (set_mip_constraints!) and the sub-group callers (set_all_smip_constraints!, set_scardmip_constraints!, set_sgcardmip_constraints!) all route through here, so builder selection lives in one place. The sub-groups leave every keyword at its default — no fees, no pinning, no sign-only branch — differing from the asset space only through sp.
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the indicators act on.wb::WeightBounds: Weight bound specification containing lower and upper bounds.lt::Option{<:Threshold}: Long-side minimum-holding threshold.st::Option{<:Threshold}: Short-side minimum-holding threshold.ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).lt_flag::Bool: Whether to apply the long-side threshold.st_flag::Bool: Whether to apply the short-side threshold.ffl::Option{<:Num_VecNum} = nothing: Long-side fixed fee rate(s).ffs::Option{<:Num_VecNum} = nothing: Short-side fixed fee rate(s).ffl_flag::Bool = false: Whether to emit long fixed fees.ffs_flag::Bool = false: Whether to emit short fixed fees.xbgt_flag::Bool = false: Whether an explicitxbgtasked to pin the decomposition (asset space only).pin_flag::Bool = false: Whether the running builder should pin the long/short decomposition.sign_only::Bool = false: Whether to use the lean sign-bit builder (asset space only).
Returns
ind::AbstractMIPIndicators: The indicator bundle of the builder that ran. Consumers read the held indicator throughheld_bin(or the gate accessors), never by key.
Related
sourcePortfolioOptimisers.set_mip_constraints! Function
set_mip_constraints!(
model::Model,
wb::WeightBounds,
card::Union{Nothing, Integer},
gcard::Union{Nothing, LinearConstraint},
pl::Union{Nothing, AbstractPhylogenyConstraintResult, AbstractVector{<:AbstractPhylogenyConstraintResult}},
lt::Union{Nothing, Threshold},
st::Union{Nothing, Threshold},
fees::Union{Nothing, Fees},
ss::Union{Nothing, Number}
)
set_mip_constraints!(
model::Model,
wb::WeightBounds,
card::Union{Nothing, Integer},
gcard::Union{Nothing, LinearConstraint},
pl::Union{Nothing, AbstractPhylogenyConstraintResult, AbstractVector{<:AbstractPhylogenyConstraintResult}},
lt::Union{Nothing, Threshold},
st::Union{Nothing, Threshold},
fees::Union{Nothing, Fees},
ss::Union{Nothing, Number},
xbgt::Bool
)Add the asset-space MIP constraints to the JuMP optimisation model and return the held indicator.
Chooses the indicator builder the requested features need (mip_constraints, short_mip_threshold_constraints, or sign_mip_constraints), then lets each feature emit against the bundle it returns: minimum-holding thresholds and fixed fees inside the builder, then cardinality, group cardinality, and pinning the long/short decomposition here. Integer phylogeny is not emitted here — it is applied late in assemble_jump_model! beside its semidefinite sibling — but its presence still forces a builder to run, so a held indicator exists for that later call to gate on. Rather than hand the bundle back as a return value, this registers it in Model State with set_mip_indicators!; the late emitter reads it with mip_indicators.
Pinning the decomposition
Two callers want the decomposition pinned, and they are the same request:
xbgt, asked for explicitly by a head whoselw/swmerely bound the weights (PartsBoundWeights).A
WeightsFromPartshead, which asks for it by construction —w = lw - swis what its parts are for — and so passes no flag.
Both route to set_exact_budget_constraints!, which reads the contract back off the model and emits what that contract needs.
Pinning needs a per-asset sign bit, which the long-only mip_constraints does not have — its ib marks an asset as held and is what cardinality counts. So an explicit xbgt is served by sign_mip_constraints when nothing else in the model needs binaries (N of them), and otherwise routed to short_mip_threshold_constraints, whose ilb/isb it reuses for free. It is ignored when the model has no short side, there being no decomposition to pin.
Arguments
model::JuMP.Model: The JuMP optimisation model.wb::WeightBounds: Weight bound specification containing lower and upper bounds.card::Option{<:Integer}: Optional maximum cardinality (number of non-zero assets).gcard::Option{<:LinearConstraint}: Optional group cardinality constraint.pl::Option{<:PlC_VecPlC}: Optional phylogeny constraint(s). Only used to detect whether anIntegerPhylogenyis present, which forces a builder to run so a held indicator is registered in Model State for the lateset_iplg_constraints!call.lt::Option{<:Threshold}: Long-side minimum-holding threshold.st::Option{<:Threshold}: Short-side minimum-holding threshold.fees::Option{<:Fees}: Optional fee specification.ss::Option{<:Number}: Big-M scaling constant (computed viaget_mip_sswhennothing).xbgt::Bool = false: Whether to pin the long/short decomposition so the budgets hold exactly. See the section above.
Returns
nothing. When a builder runs, its bundle is registered in Model State viaset_mip_indicators!for the lateset_iplg_constraints!call to gate on; when none does (the no-MIP-features early return) nothing is registered andmip_indicatorsstaysnothing.
Related