JuMP model optimisation
PortfolioOptimisers.jl is based on JuMP, as such it tries to be as flexible as possible.
These types and functions let us define solver and solution interfaces.
PortfolioOptimisers.Solver — Type
struct Solver{__T_name, __T_solver, __T_settings, __T_check_sol, __T_add_bridges} <: AbstractEstimatorConfigures one solver backend, its attributes, and the statuses its solutions must reach.
Every optimiser takes one Solver or a vector of them. optimise_JuMP_model! tries them in order and stops at the first that returns a solution check_sol accepts, so a vector is a fallback chain.
Fields
name: Symbol or string identifier. It is also the key under whichoptimise_JuMP_model!files this solver's failure inJuMPResult'strials, so two solvers that share a name share one entry and the later failure overwrites the earlier one. Give each solver of a vector its own name, because the default""is shared by all of them.
solver: Theoptimizer_factoryinset_optimizer.
settings: Optional solver-specific settings used inset_attribute.
check_sol: Named tuple of keyword arguments splatted intoassert_is_solved_and_feasibleafter each solve. It decides which solver statuses count as a solved model. The default(;)accepts JuMP's own defaults,allow_local = trueandallow_almost = false: the termination status must beOPTIMALorLOCALLY_SOLVED, and the primal status must beFEASIBLE_POINT. The strictness is deliberate — a solution the solver itself flags as approximate is rejected rather than silently accepted, so a solver stage that fails this check falls through to the next solver in the vector. The common relaxation ischeck_sol = (; allow_local = true, allow_almost = true), which also acceptsALMOST_OPTIMAL,ALMOST_LOCALLY_SOLVEDandNEARLY_FEASIBLE_POINT; it is what the examples, the user guide and the test suite pass, because a first-order solver reaching its tolerance on a well-posed portfolio problem is usually good enough. Go the other way withallow_local = falseto rejectLOCALLY_SOLVEDand demand a certified global optimum, and adddual = trueto also require a feasible dual point.
add_bridges: Theadd_bridgeskeyword argument inset_optimizer.
Constructors
Solver(; name::Sym_Str = "", solver::Any, settings::Option{<:SlvSettings} = nothing, check_sol::NamedTuple = (;), add_bridges::Bool = true) -> SolverKeywords correspond to the struct's fields.
Validation
- If not
nothing,!isempty(settings).
Examples
The default check_sol is strict — it accepts only a solution the solver reports as OPTIMAL or LOCALLY_SOLVED at a FEASIBLE_POINT.
julia> Solver(; solver = nothing)Solver name ┼ String: "" solver ┼ nothing settings ┼ nothing check_sol ┼ @NamedTuple{}: NamedTuple() add_bridges ┴ Bool: trueTo also accept an approximate solution, which is the common case and what the examples, user guide and tests use:
julia> Solver(; solver = nothing, check_sol = (; allow_local = true, allow_almost = true))Solver name ┼ String: "" solver ┼ nothing settings ┼ nothing check_sol ┼ @NamedTuple{allow_local::Bool, allow_almost::Bool}: (allow_local = true, allow_almost = true) add_bridges ┴ Bool: trueRelated
PortfolioOptimisers.JuMPResult — Type
struct JuMPResult{__T_trials, __T_success} <: AbstractJuMPResultRecords which solvers failed, at which stage, and whether any of them succeeded.
When success is false the constructor emits a warning built by failed_solve_msg: one bounded line per failed solver stage (name, stage, first line of the error). The full per-solver exceptions and settings stay available on trials and are never dumped into the log.
trials records failures only. A solver that succeeds leaves no entry, so an empty trials with success = true means the first solver answered, and it is not a record of the solve. Each entry is keyed by the solver's name and holds a dictionary from the failed stage — :set_optimizer, :optimize! or :assert_is_solved_and_feasible — to the exception. Two solvers that share a name share one entry, and the default name is "" for all of them, so a vector of unnamed solvers keeps only its last failure.
Fields
trials: Dictionary of solver trials and errors.
success: Boolean indicating whether optimisation succeeded.
Constructors
JuMPResult(; trials::AbstractDict, success::Bool) -> JuMPResultKeywords correspond to the struct's fields.
Examples
julia> JuMPResult(; trials = Dict(:HiGHS => Dict(:optimize! => "error")), success = true)JuMPResult trials ┼ Dict{Symbol, Dict{Symbol, String}}: Dict(:HiGHS => Dict(:optimize! => "error")) success ┴ Bool: trueRelated