API References
Core types
Missing docstring for BLProblem. Check Documenter's build log for details.
BilevelHeuristics.BLInformation — TypeBLInformation(; ul = Information(), ll = Information())Stores runtime information (best / worst function values, feasible ratios, etc.) for both the upper and lower levels. Used internally for termination checks and logging.
Fields
ul—Metaheuristics.Informationfor the upper level.ll—Metaheuristics.Informationfor the lower level.
BilevelHeuristics.BLOptions — TypeBLOptions(; ul = Options(), ll = Options())Configuration settings (population size, iteration budget, tolerances, verbosity, etc.) for both the upper and lower levels.
Fields
ul—Metaheuristics.Optionsfor the upper level (e.g.f_calls_limit,iterations,f_tol,verbose,seed,store_convergence).ll—Metaheuristics.Optionsfor the lower level.
Example
options = BLOptions(
ul = Options(f_calls_limit = 10_000, verbose = true),
ll = Options(f_calls_limit = 50_000),
)Missing docstring for BLAlgorithm. Check Documenter's build log for details.
BilevelHeuristics.BLState — TypeBLState{T}The result of a bilevel optimisation run. Returned by optimize.
Fields
best_sol— the bestBLIndividualfound (according to the algorithm's comparison criterion).population— the final population ofBLIndividuals.F_calls,f_calls— number of upper- and lower-level function evaluations.iteration— number of completed iterations.convergence— history ofBLStatesnapshots (ifstore_convergenceis enabled in options).start_time,final_time,overall_time— timing information (seconds).stop— whether the run stopped.stop_msg— termination reason string.
Extracting results
Use minimum and minimizer to get the objective values and decision vectors of the best solution:
Fmin, fmin = minimum(res) # (F, f) at the best solution
x, y = minimizer(res) # (x, y) at the best solutionMain interface
Metaheuristics.optimize — Function optimize(
f::Function, # objective function
search_space,
method::AbstractAlgorithm = ECA();
logger::Function = (status) -> nothing,
)Minimize a n-dimensional function f with domain search_space (2×n matrix) using method = ECA() by default.
Example
Minimize f(x) = Σx² where x ∈ [-10, 10]³.
Solution:
julia> f(x) = sum(x.^2)
f (generic function with 1 method)
julia> bounds = [ -10.0 -10 -10; # lower bounds
10.0 10 10 ] # upper bounds
2×3 Array{Float64,2}:
-10.0 -10.0 -10.0
10.0 10.0 10.0
julia> result = optimize(f, bounds)
+=========== RESULT ==========+
iteration: 1429
minimum: 2.5354499999999998e-222
minimizer: [-1.5135301653303966e-111, 3.8688354844737692e-112, 3.082095708730726e-112]
f calls: 29989
total time: 0.1543 s
+============================+optimize(F, f, bounds_ul, bounds_ll, method = BCA(); logger = (status) -> nothing)Solve a bilevel optimization problem using a heuristic or metaheuristic method.
The upper-level problem is min_x F(x, y) subject to x ∈ bounds_ul and any upper-level constraints returned by F, while y must be an optimal solution of the lower-level problem min_y f(x, y) subject to y ∈ bounds_ll and its own constraints.
Parameters
F(x, y)— upper-level objective function. Must return one of:- scalar value (unconstrained),
(fval, g, h)tuple whereg/hare vectors of inequality / equality constraints.
f(x, y)— lower-level objective function (same signature asF).bounds_ul— upper-level bounds, a2 × D_ulmatrix where row 1 = lower bounds, row 2 = upper bounds.bounds_ll— lower-level bounds, a2 × D_llmatrix (same layout).method— a bilevel algorithm, e.g.BCA,QBCA,SABO,SMS_MOBO, etc. (default:BCA()).logger— a functionstatus -> ...called at the end of every iteration (useful for custom logging or visualisation).
Returns
A BLState object containing the best solution found, the final population, convergence history, and function evaluation counts. Use minimum and minimizer to extract results.
Example (single-objective, unconstrained)
F(x, y) = sum(x.^2) + sum(y.^2)
f(x, y) = sum((x - y).^2) + y[1]^2
bounds = [-ones(5)'; ones(5)']
res = optimize(F, f, bounds, bounds, BCA())
x, y = minimizer(res)
Fmin, fmin = minimum(res)Example (constrained)
function F(x, y)
fval = sum(x.^2) + sum(y.^2)
g = [x[1] + x[2] - 1, x[3] - y[3] - 10] # inequality constraints
h = [0.0] # equality constraints
return fval, g, h
end
function f(x, y)
fval = sum((x - y).^2) + y[1]^2
g = [x[2] - y[1]^2 - 5]
h = [0.0]
return fval, g, h
end
bounds_ul = [-ones(5) ones(5)]
bounds_ll = [-ones(5) ones(5)]
res = optimize(F, f, bounds_ul, bounds_ll, BCA())Example (multi-objective)
function F(x, y) # two upper-level objectives
[y[1] - x[1], y[2]], [-1.0 - sum(y)], [0.0]
end
function f(x, y) # two lower-level objectives
y, [-x[1]^2 + sum(y .^ 2)], [0.0]
end
bounds_ul = [0.0 1.0]'
bounds_ll = [-1 -1; 1 1.0]
res = optimize(F, f, bounds_ul, bounds_ll, SMS_MOBO())Base.minimum — Functionminimum(f, itr; [init])Returns the smallest result of calling function f on each element of itr.
The value returned for empty itr can be specified by init. It must be a neutral element for min (i.e. which is greater than or equal to any other element) as it is unspecified whether init is used for non-empty collections.
Keyword argument init requires Julia 1.6 or later.
Examples
julia> minimum(length, ["Julion", "Julia", "Jule"])
4
julia> minimum(length, []; init=typemax(Int64))
9223372036854775807
julia> minimum(sin, Real[]; init=1.0) # good, since output of sin is <= 1
1.0minimum(itr; [init])Returns the smallest element in a collection.
The value returned for empty itr can be specified by init. It must be a neutral element for min (i.e. which is greater than or equal to any other element) as it is unspecified whether init is used for non-empty collections.
Keyword argument init requires Julia 1.6 or later.
Examples
julia> minimum(-20.5:10)
-20.5
julia> minimum([1,2,3])
1
julia> minimum([])
ERROR: ArgumentError: reducing over an empty collection is not allowed
Stacktrace:
[...]
julia> minimum([]; init=Inf)
Infminimum(A::AbstractArray; dims)Compute the minimum value of an array over the given dimensions. See also the min(a,b) function to take the minimum of two or more arguments, which can be applied elementwise to arrays via min.(a,b).
See also: minimum!, extrema, findmin, argmin.
Examples
julia> A = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> minimum(A, dims=1)
1×2 Matrix{Int64}:
1 2
julia> minimum(A, dims=2)
2×1 Matrix{Int64}:
1
3minimum(f, A::AbstractArray; dims)Compute the minimum value by calling the function f on each element of an array over the given dimensions.
Examples
julia> A = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> minimum(abs2, A, dims=1)
1×2 Matrix{Int64}:
1 4
julia> minimum(abs2, A, dims=2)
2×1 Matrix{Int64}:
1
9minimum(state::Metaheuristics.State)Returns the approximation to the minimum (min f(x)) stored in state.
minimum(status::BLState) -> (Fval, fval)Return the upper- and lower-level objective values of the best solution found.
BilevelHeuristics.minimizer — Functionminimizer(status::BLState) -> (x, y)Return the upper- and lower-level decision vectors of the best solution found.
Solution accessors
BilevelHeuristics.ulvector — Functionulvector(A)Extract the upper-level decision vector x from a BLIndividual.
BilevelHeuristics.llvector — Functionllvector(A)Extract the lower-level decision vector y from a BLIndividual.
Missing docstring for leader_pos. Check Documenter's build log for details.
Missing docstring for follower_pos. Check Documenter's build log for details.
BilevelHeuristics.ulfval — Functionulfval(A)Extract the upper-level objective value F(x, y) from a BLIndividual.
BilevelHeuristics.llfval — Functionllfval(A)Extract the lower-level objective value f(x, y) from a BLIndividual.
Missing docstring for leader_f. Check Documenter's build log for details.
Missing docstring for follower_f. Check Documenter's build log for details.
Population accessors
BilevelHeuristics.get_ul_population — Functionget_ul_population(population)Return the upper-level solutions from a population of BLIndividuals.
BilevelHeuristics.get_ll_population — Functionget_ll_population(population)Return the lower-level solutions from a population of BLIndividuals.
BilevelHeuristics.ulpositions — Functionulpositions(population)Extract the upper-level decision vectors from every solution in population. Returns an N × D_ul matrix.
BilevelHeuristics.llpositions — Functionllpositions(population)Extract the lower-level decision vectors from every solution in population. Returns an N × D_ll matrix.
BilevelHeuristics.ulfvals — Functionulfvals(pop)Extract all upper-level objective values from population. Returns a vector of length N (single-objective) or an N × M matrix (multi-objective).
BilevelHeuristics.llfvals — Functionllfvals(pop)Extract all lower-level objective values from population. Returns a vector of length N (single-objective) or an N × M matrix (multi-objective).
BilevelHeuristics.ulgvals — Functionulgvals(pop)Extract upper-level inequality constraint values G(x, y) for each solution in population. Returns an N × n_ineq matrix.
BilevelHeuristics.llgvals — Functionllgvals(pop)Extract lower-level inequality constraint values g(x, y) for each solution in population. Returns an N × n_ineq matrix.
BilevelHeuristics.ulhvals — Functionulhvals(pop)Extract upper-level equality constraint values H(x, y) for each solution in population. Returns an N × n_eq matrix.
BilevelHeuristics.llhvals — Functionllhvals(pop)Extract lower-level equality constraint values h(x, y) for each solution in population. Returns an N × n_eq matrix.
Validation
BilevelHeuristics.is_pseudo_feasible — Functionis_pseudo_feasible(A, B, δ1, δ2, ε1, ε2)Check whether A is a pseudo-feasible solution with respect to B.
A solution (x_A, y_A) is pseudo-feasible relative to (x_B, y_B) when:
- The upper-level objectives are close:
|F(A) - F(B)| < ε1. - The lower-level objectives are close:
|f(A) - f(B)| < ε2. - The upper-level positions are close:
|x_A - x_B| < δ1. - The lower-level positions are distant:
|y_A - y_B| > δ2.
This indicates that the two solutions have similar objective values at both levels but different lower-level responses — a sign of multi-modality at the lower level. Such solutions can mislead the search, and algorithms like QBCA2 explicitly avoid them.