PSO Global Optimizer Benchmarks
This benchmark compares the PSO variants from ParallelParticleSwarms.jl against established global optimizers on the BlackBoxOptimizationBenchmarking.jl (BBOB) suite through the Optimization.jl interface. It uses the reference Black-Box Global Optimizer Benchmarks protocol and its first-hit wall-clock measurement. Differences: three BBOB functions that crash the GPU kernels are excluded, and this is a reduced configuration: 10 trials and 15 budgets from 10 to 10,000, versus the reference's 40 trials and 30 budgets to 100,000.
How it works
Every BBOB function has a known minimum f_opt. A run succeeds if it finds a point with objective below f_opt + 1e-6. Two experiments are run:
- Budget experiment. Each optimizer is run from scratch at 15 iteration budgets (10 to 10,000), 10 times per budget, on every function. Each run records success, distance to the true minimizer, and number of objective evaluations. This feeds the iteration, evaluations, heatmap and distance plots. Success rates are pooled over dimensions 3, 5 and 10.
- Time-to-success experiment. Each optimizer gets one run per (function, trial) with a 10,000-iteration budget, and we record the wall-clock time at which it first reached the target. From those times we build a CDF: for a time budget T, what fraction of runs were solved within T seconds. This feeds the wall-clock plot and the relative-runtime bar chart.
Everything is evaluated in Float64: BBOB's f_opt is of order 100 and eps(100f0) ≈ 8e-6 is larger than the 1e-6 target, so a Float32 objective could never register success. Results are pooled over dimensions 3, 5 and 10.
Setup
using Random; Random.seed!(42)
using BlackBoxOptimizationBenchmarking, CairoMakie, Optimization, Memoize, Statistics
using StaticArrays, LinearAlgebra, ForwardDiff, KernelAbstractions, CUDA
using OptimizationBBO, OptimizationOptimJL, OptimizationEvolutionary, OptimizationNLopt
using OptimizationMetaheuristics, OptimizationSciPy
using OptimizationOptimJL: Optim # NelderMead and SAMIN live here
using ParallelParticleSwarms
CairoMakie.activate!()
import BlackBoxOptimizationBenchmarking: Chain, BenchmarkSetup, BenchmarkResults,
BBOBFunction, FunctionCallsCounter, solve_problem, pinit, compute_CI
const BBOB = BlackBoxOptimizationBenchmarking
const SciMLBase = Optimization.SciMLBase
const PSOKernel = ParallelParticleSwarms.ParallelPSOKernel
const SyncPSOKernel = ParallelParticleSwarms.ParallelSyncPSOKernel
const SerialPSO = ParallelParticleSwarms.SerialPSO
const HybridPSO = ParallelParticleSwarms.HybridPSO
const BACKEND = CUDABackend()
const DIMENSIONS = (3, 5, 10)
const NTRIALS = 10
const Δf = 1.0e-6
const NUM_PARTICLES = 50_000 # GPU swarm
const SERIAL_PARTICLES = 512 # CPU swarm
const RUN_LENGTH = round.(Int, 10 .^ LinRange(1, 4, 15)) # budget experiment
const MAX_TTS_ITERS = 10_000 # time-to-success experiment
const TTS_CHUNK = 20 # GPU: read back the best cost every this many iterations
# f4, f7, f10 crash the GPU kernels and are excluded.
suite(D) = filter(f -> nameof(f.f) ∉ (:f4, :f7, :f10), BBOB.bbob_suite(Val(D)))
const SUITES = (suite(3), suite(5), suite(10))
const TEST_FUNCTIONS = first(SUITES) # names/order for the heatmap; rates pool all three D17-element Vector{BlackBoxOptimizationBenchmarking.BBOBFunction}:
F1 Sphere
F2 Ellipsoidal
F3 Rastrigin
F5 Linear Slope
F6 Attractive Sector
F8 Rosenbrock
F9 Rosenbrock Rotated
F11 Discus
F12 Bent Cigar
F13 Sharp Ridge
F14 Different Powers
F15 Rastrigin 2
F16 Weierstrass
F17 Schaffers F7
F18 Schaffers F7 Ill-Cond
F19 Griewank-Rosenbrock
F20 SchwefelOptimizers
Baselines are chained: 90% of the budget to the global method, 10% to a Nelder-Mead polish. setup maps each label to a constructor, and every run (warm-ups included) builds a fresh optimizer: Metaheuristics' DE and ECA keep their population between solves, so a reused instance carries a 3-dimensional population into the 5- and 10-dimensional problems.
chain(t; isboxed = false) =
Chain(BenchmarkSetup(t; isboxed), BenchmarkSetup(Optim.NelderMead(); isboxed = false), 0.9)
setup = Dict(
"NelderMead" => () -> BenchmarkSetup(Optim.NelderMead()),
"NLopt.GN_CRS2_LM()" => () -> chain(NLopt.GN_CRS2_LM(), isboxed = true),
"NLopt.GN_DIRECT()" => () -> chain(NLopt.GN_DIRECT(), isboxed = true),
"NLopt.GN_ESCH()" => () -> chain(NLopt.GN_ESCH(), isboxed = true),
"OptimizationEvolutionary.GA()" => () -> chain(OptimizationEvolutionary.GA(), isboxed = true),
"OptimizationEvolutionary.DE()" => () -> chain(OptimizationEvolutionary.DE(), isboxed = true),
"OptimizationEvolutionary.ES()" => () -> chain(OptimizationEvolutionary.ES(), isboxed = true),
"Optim.SAMIN" => () -> chain(Optim.SAMIN(verbosity = 0), isboxed = true),
"BBO_adaptive_de_rand_1_bin" => () -> chain(BBO_adaptive_de_rand_1_bin(), isboxed = true),
"BBO_de_rand_2_bin" => () -> chain(BBO_de_rand_2_bin(), isboxed = true),
"OptimizationMetaheuristics.ECA" => () -> chain(OptimizationMetaheuristics.ECA(), isboxed = true),
"OptimizationMetaheuristics.DE" => () -> chain(OptimizationMetaheuristics.DE(), isboxed = true),
"ScipyDifferentialEvolution" => () -> chain(ScipyDifferentialEvolution(), isboxed = true),
"SerialPSO" => () -> SerialPSO(SERIAL_PARTICLES),
"PSOKernel" => () -> PSOKernel(NUM_PARTICLES; backend = BACKEND, global_update = true),
"SyncPSOKernel" => () -> SyncPSOKernel(NUM_PARTICLES; backend = BACKEND),
"HybridPSO_LBFGS" => () -> HybridPSO(pso = SyncPSOKernel(NUM_PARTICLES; backend = BACKEND); backend = BACKEND),
)
const LABELS = collect(keys(setup))
const PSO_KEYS = Set(["SerialPSO", "PSOKernel", "SyncPSOKernel", "HybridPSO_LBFGS"])
particles_of(algo) = algo == "SerialPSO" ? SERIAL_PARTICLES : NUM_PARTICLESparticles_of (generic function with 1 method)PSO plumbing
PSO needs SVector inputs and a penalty for points outside the box. The penalty must also accept ForwardDiff Duals, which HybridPSO's L-BFGS phase uses.
_value(x::Real) = x
_value(x::ForwardDiff.Dual) = ForwardDiff.value(x)
_to_f64(x) = Float64(_value(x))
function pso_objective(f::BBOBFunction, x)
any(xi -> !isfinite(_value(xi)) || abs(_value(xi)) > 15, x) && return zero(first(x)) + 1.0e10
return f(x)
end
# `obj` is any x -> objective callable. u0 only fixes type and dimension; the swarm is
# sampled from the box.
function pso_problem(obj, ::Val{D}) where {D}
optf = OptimizationFunction{false}((x, p) -> obj(x), SciMLBase.NoAD())
lb = SVector{D, Float64}(ntuple(_ -> -5.5, Val(D))) # same box as the baselines
ub = SVector{D, Float64}(ntuple(_ -> 5.5, Val(D)))
return OptimizationProblem{false}(optf, SVector{D, Float64}(pinit(D)), nothing; lb, ub)
end
pso_problem(obj, f::BBOBFunction{F, N}) where {F, N} = pso_problem(obj, Val(N))
pso_solve(opt, prob, budget) = opt isa HybridPSO ?
solve(prob, opt; maxiters = budget, local_maxiters = 50, abstol = 1.0e-8, reltol = 1.0e-8) :
solve(prob, opt; maxiters = budget)pso_solve (generic function with 1 method)Experiment 1: success rate vs. budget
run_one(algo, f, budget) returns (objective, minimizer, evaluations). One loop over (dimension, function, budget, trial); success, distance and evaluations are then averaged across dimensions 3, 5 and 10.
function run_one(algo, f::BBOBFunction, budget::Int)
if algo in PSO_KEYS
sol = pso_solve(setup[algo](), pso_problem(x -> pso_objective(f, x), f), budget)
u = sol.u isa AbstractVector ? sol.u : sol.u[]
return _to_f64(sol.objective), u, budget * particles_of(algo)
else
counted = FunctionCallsCounter(f)
sol = solve_problem(setup[algo](), counted, length(f.x_opt), budget)
return sol.objective, sol.u, counted.count
end
end
function benchmark(algo)
Nf = length(TEST_FUNCTIONS)
Nd = length(SUITES)
success = zeros(Nf, length(RUN_LENGTH)); dist = zeros(Nf, length(RUN_LENGTH))
calls = zeros(Nf, length(RUN_LENGTH))
for funcs in SUITES, (fi, f) in enumerate(funcs)
run_one(algo, f, 10) # warm-up per (function, D): compile, discard
for (ri, rl) in enumerate(RUN_LENGTH), _ in 1:NTRIALS
fval, u, n = run_one(algo, f, rl)
success[fi, ri] += fval < f.f_opt + Δf
dist[fi, ri] += norm(u .- f.x_opt)
calls[fi, ri] += n
end
end
success ./= NTRIALS * Nd
dist ./= NTRIALS * Nd
calls ./= NTRIALS * Nd
sr = vec(mean(success, dims = 1))
Neff = NTRIALS * Nf * Nd
qlow, qhigh = compute_CI(sr, Neff, 0.25)
return BenchmarkResults(;
run_length = collect(RUN_LENGTH),
success_count = round.(Int, sr .* Neff),
success_rate = sr,
success_rate_qlow = qlow,
success_rate_qhigh = qhigh,
distance_to_minimizer = vec(mean(dist, dims = 1)),
minimum = fill(NaN, length(RUN_LENGTH)),
runtime = 0.0,
Neffective = Neff,
callcount = vec(mean(calls, dims = 1)),
success_rate_per_function = success[:, end],
)
end
@memoize run_bench(algo) = benchmark(algo)
results = Dict{String, BenchmarkResults}()
for algo in LABELS
algo in PSO_KEYS && (results[algo] = run_bench(algo))
end # GPU first
for algo in LABELS
algo in PSO_KEYS || (results[algo] = run_bench(algo))
end
[results[l] for l in LABELS]17-element Vector{BlackBoxOptimizationBenchmarking.BenchmarkResults}:
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.00196078, 0.00392157, 0.00392157, 0.00196078, 0.0137255,
0.0176471, 0.0235294, 0.0313725, 0.0509804, 0.0666667, 0.160784, 0.237255,
0.280392, 0.335294, 0.394118]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.00980392, 0.00784314, 0.0235294, 0.0313725, 0.054902, 0.0
764706, 0.188235, 0.239216, 0.303922, 0.354902, 0.378431, 0.423529, 0.48823
5, 0.494118, 0.521569]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.00196078, 0.00196078, 0.00196078, 0.00392157, 0.00980392,
0.0215686, 0.0235294, 0.0352941, 0.0588235, 0.109804, 0.209804, 0.294118,
0.364706, 0.403922, 0.486275]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0, 0.0, 0.00196078, 0.00588235, 0.0117647, 0.0215686, 0.0
235294, 0.0333333, 0.0607843, 0.103922, 0.227451, 0.303922, 0.398039, 0.447
059, 0.507843]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0, 0.0196078, 0.0196078, 0.0196078, 0.0392157, 0.0392157,
0.0588235, 0.0588235, 0.0784314, 0.137255, 0.215686, 0.333333, 0.411765, 0
.411765, 0.54902]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.00392157, 0.00196078, 0.0, 0.00196078, 0.00784314, 0.0156
863, 0.0313725, 0.0294118, 0.0588235, 0.0686275, 0.17451, 0.247059, 0.33921
6, 0.392157, 0.441176]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.027451, 0.0392157, 0.0411765, 0.0588235, 0.0784314, 0.111
765, 0.194118, 0.313725, 0.460784, 0.484314, 0.584314, 0.588235, 0.598039,
0.619608, 0.647059]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0, 0.0, 0.0, 0.0, 0.00196078, 0.00784314, 0.0137255, 0.02
35294, 0.0411765, 0.0588235, 0.113725, 0.209804, 0.266667, 0.317647, 0.3627
45]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0588235, 0.0588235, 0.0882353, 0.182353, 0.356863, 0.5019
61, 0.578431, 0.609804, 0.615686, 0.62549, 0.641176, 0.668627, 0.682353, 0.
688235, 0.701961]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.315686, 0.301961, 0.335294, 0.331373, 0.345098, 0.352941,
0.341176, 0.331373, 0.366667, 0.37451, 0.423529, 0.435294, 0.478431, 0.515
686, 0.515686]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0588235, 0.0627451, 0.0921569, 0.180392, 0.378431, 0.5098
04, 0.594118, 0.596078, 0.601961, 0.647059, 0.647059, 0.666667, 0.666667, 0
.680392, 0.682353]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0588235, 0.0588235, 0.0588235, 0.0764706, 0.152941, 0.3,
0.398039, 0.427451, 0.439216, 0.435294, 0.478431, 0.523529, 0.541176, 0.543
137, 0.578431]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0333333, 0.0411765, 0.0529412, 0.0588235, 0.0823529, 0.14
3137, 0.192157, 0.213725, 0.243137, 0.296078, 0.339216, 0.34902, 0.409804,
0.464706, 0.44902]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.686275, 0.686275, 0.694118, 0.731373, 0.778431, 0.790196,
0.784314, 0.778431, 0.784314, 0.764706, 0.766667, 0.762745, 0.758824, 0.76
0784, 0.756863]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0235294, 0.0294118, 0.0392157, 0.0568627, 0.188235, 0.325
49, 0.454902, 0.621569, 0.7, 0.729412, 0.731373, 0.77451, 0.752941, 0.73725
5, 0.74902]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0, 0.00196078, 0.00196078, 0.00588235, 0.0196078, 0.02352
94, 0.0352941, 0.0411765, 0.0627451, 0.170588, 0.25098, 0.339216, 0.407843,
0.513725, 0.6]
BenchmarkResults :
Run length : [10, 16, 27, 44, 72, 118, 193, 316, 518, 848, 1389, 2276, 3728
, 6105, 10000]
Success rate : [0.0, 0.0, 0.00392157, 0.0117647, 0.027451, 0.0372549, 0.037
2549, 0.0392157, 0.0627451, 0.127451, 0.215686, 0.282353, 0.35098, 0.401961
, 0.452941]Experiment 2: wall-clock time to success
One run per (dimension, function, trial) at MAX_TTS_ITERS; record the time of the first hit. The CDF pools dimensions 3, 5 and 10.
- CPU optimizers (baselines,
SerialPSO): the objective is wrapped in a closure that stamps the clock on the first evaluation below the target. This is the reference's method. - GPU optimizers: a kernel cannot call
time(), so the swarm is advanced in chunks ofTTS_CHUNKiterations and the best cost is read back on the host in between. The swarm lives in the solver cache, so this is one continuous run with a time resolution of one chunk. ForHybridPSOthe PSO phase is chunked the same way; if it never hits, the L-BFGS phase runs from the final swarm and its finish time is used.
The clock starts before the optimizer's own setup in every case, and one untimed warm-up run per (optimizer, function, dimension) keeps compilation out of the numbers, since the kernels specialize on the objective and on D.
# Wrap an objective so the first evaluation below `target` records the elapsed time.
function tracked(obj, target, t0)
hit = Ref(Inf)
g(x) = (v = obj(x); v < target && hit[] == Inf && (hit[] = time() - t0); v)
return g, hit
end
# Advance a PSO cache in chunks; return the time of the first chunk whose best cost is
# below `target`, or Inf. (solve! resets the inertia weight each call; harmless with the
# default wdamp = 1.)
function chunked!(cache, target, t0)
for _ in 1:cld(MAX_TTS_ITERS, TTS_CHUNK)
sol = SciMLBase.solve!(cache; maxiters = TTS_CHUNK)
if cache.alg isa SyncPSOKernel # sync kernel does not store gbest back
obj = _to_f64(sol.objective)
cache.gbest = ParallelParticleSwarms.SPSOGBest(sol.u, obj)
end
_to_f64(sol.objective) < target && return time() - t0
end
return Inf
end
function time_to_success_one(algo, f::BBOBFunction)
opt, target = setup[algo](), f.f_opt + Δf
t0 = time()
if !(algo in PSO_KEYS)
g, hit = tracked(f, target, t0)
solve_problem(opt, g, length(f.x_opt), MAX_TTS_ITERS)
return hit[]
elseif opt isa SerialPSO
g, hit = tracked(x -> pso_objective(f, x), target, t0)
pso_solve(opt, pso_problem(g, f), MAX_TTS_ITERS)
return hit[]
elseif opt isa HybridPSO
cache = SciMLBase.init(pso_problem(x -> pso_objective(f, x), f), opt)
t = chunked!(cache.pso_cache, target, t0) # PSO phase
isfinite(t) && return t
sol = SciMLBase.solve!(cache; maxiters = 0, local_maxiters = 50, abstol = 1.0e-8, reltol = 1.0e-8)
return _to_f64(sol.objective) < target ? time() - t0 : Inf # L-BFGS phase only
else
cache = SciMLBase.init(pso_problem(x -> pso_objective(f, x), f), opt)
return chunked!(cache, target, t0)
end
end
function time_to_success(algo)
times = Float64[]
for funcs in SUITES, f in funcs
time_to_success_one(algo, f) # warm-up per (function, D): compile, discard
for _ in 1:NTRIALS
push!(times, time_to_success_one(algo, f))
end
end
return times
end
@memoize run_tts(algo) = time_to_success(algo)
tts = Dict{String, Vector{Float64}}()
for algo in LABELS
algo in PSO_KEYS && (tts[algo] = run_tts(algo))
end
for algo in LABELS
algo in PSO_KEYS || (tts[algo] = run_tts(algo))
endusing Printf
for l in sort(collect(keys(results)))
v = filter(isfinite, tts[l])
@printf "%-28s final success = %.3f solved = %3d/%d median TTS = %s\n" l results[l].success_rate[end] length(v) length(tts[l]) (isempty(v) ? "never" : @sprintf("%.3f s", median(v)))
endBBO_adaptive_de_rand_1_bin final success = 0.508 solved = 261/510 med
ian TTS = 0.006 s
BBO_de_rand_2_bin final success = 0.486 solved = 244/510 med
ian TTS = 0.005 s
HybridPSO_LBFGS final success = 0.757 solved = 391/510 med
ian TTS = 0.012 s
NLopt.GN_CRS2_LM() final success = 0.600 solved = 294/510 med
ian TTS = 0.004 s
NLopt.GN_DIRECT() final success = 0.549 solved = 280/510 med
ian TTS = 0.012 s
NLopt.GN_ESCH() final success = 0.441 solved = 229/510 med
ian TTS = 0.008 s
NelderMead final success = 0.522 solved = 250/510 med
ian TTS = 0.000 s
Optim.SAMIN final success = 0.453 solved = 230/510 med
ian TTS = 0.011 s
OptimizationEvolutionary.DE() final success = 0.449 solved = 241/510 me
dian TTS = 0.003 s
OptimizationEvolutionary.ES() final success = 0.363 solved = 184/510 me
dian TTS = 0.000 s
OptimizationEvolutionary.GA() final success = 0.394 solved = 193/510 me
dian TTS = 0.000 s
OptimizationMetaheuristics.DE final success = 0.647 solved = 330/510 me
dian TTS = 0.007 s
OptimizationMetaheuristics.ECA final success = 0.749 solved = 383/510 m
edian TTS = 0.006 s
PSOKernel final success = 0.702 solved = 362/510 med
ian TTS = 0.010 s
ScipyDifferentialEvolution final success = 0.516 solved = 254/510 med
ian TTS = 0.078 s
SerialPSO final success = 0.578 solved = 293/510 med
ian TTS = 0.012 s
SyncPSOKernel final success = 0.682 solved = 353/510 med
ian TTS = 0.011 sPlots
const MARKERS = [
:circle, :rect, :utriangle, :diamond, :dtriangle, :pentagon, :cross,
:xcross, :star4, :star5, :hexagon, :star6, :ltriangle, :rtriangle,
]
const LINESTYLES = [:solid, :dash, :dot, :dashdot, (:dot, :dense)]
const STYLE = Dict(l => (MARKERS[mod1(i, end)], LINESTYLES[mod1(i, end)]) for (i, l) in enumerate(LABELS))
# xs, ys: Dict label => vector. Legend ordered by each curve's final y value.
function plot_curves(xs, ys; xlabel, ylabel, xlims = (nothing, nothing), ylims = (0, 1), best_is_high = true)
order = sort(collect(keys(ys)); by = l -> ys[l][end], rev = best_is_high)
fig = Figure(size = (1100, 450))
ax = Axis(fig[1, 1]; xscale = log10, xlabel, ylabel, limits = (xlims..., ylims...))
for l in order
marker, linestyle = STYLE[l]
scatterlines!(ax, xs[l], ys[l]; label = l, marker, linestyle, linewidth = 2, markersize = 6)
end
Legend(fig[1, 2], ax; framevisible = false)
return fig
endplot_curves (generic function with 1 method)Success rate vs. iterations
Higher and further left is better. One PSO iteration moves every particle (50,000 evaluations on the GPU); one Nelder-Mead step is a few evaluations, so this view favours parallel methods.
plot_curves(
Dict(l => Float64.(RUN_LENGTH) for l in LABELS),
Dict(l => results[l].success_rate for l in LABELS);
xlabel = "Iterations", ylabel = "Success rate", xlims = (1, maximum(RUN_LENGTH))
)
Success rate vs. function evaluations
Same y-axis, x is the number of objective calls: the fair measure of work done. HybridPSO_LBFGS is omitted here because its L-BFGS phase runs on the GPU, where its evaluations cannot be counted; its swarm-only count would understate the work.
evals_labels = filter(!=("HybridPSO_LBFGS"), LABELS)
plot_curves(
Dict(l => results[l].callcount for l in evals_labels),
Dict(l => results[l].success_rate for l in evals_labels);
xlabel = "Function evaluations", ylabel = "Success rate", xlims = (1, 1.0e9)
)
Success rate vs. wall-clock time
For a time budget T (x), the fraction of (function, trial) runs that had already reached the target by T seconds (y). A curve that plateaus below 1 never solved the remaining problems within MAX_TTS_ITERS. This is where the GPU gets credit for cheap evaluations.
finite = filter(isfinite, reduce(vcat, values(tts); init = Float64[]))
isempty(finite) && (finite = [1.0e-3, 1.0e3]) # nothing succeeded; keep the plot alive
thresholds = 10 .^ range(log10(minimum(finite) / 2), log10(maximum(finite) * 2), length = 50)
cdf(times) = [count(<=(T), times) / length(times) for T in thresholds]
plot_curves(
Dict(l => thresholds for l in LABELS),
Dict(l => cdf(tts[l]) for l in LABELS);
xlabel = "Wall time (s)", ylabel = "Success rate"
)
Success rate per function
One row per optimizer (worst at the bottom), one column per function, at the largest budget, pooled over dimensions 3, 5 and 10.
M = reduce(hcat, results[l].success_rate_per_function for l in LABELS) # functions × optimizers
order = sortperm(vec(mean(M, dims = 1)))
fig = Figure(size = (1150, 600))
ax = Axis(
fig[1, 1]; xticks = (1:length(TEST_FUNCTIONS), string.(TEST_FUNCTIONS)),
yticks = (1:length(LABELS), LABELS[order]), xticklabelrotation = π / 4
)
hm = heatmap!(ax, M[:, order]; colormap = :RdYlGn, colorrange = (0, 1))
Colorbar(fig[1, 2], hm; label = "Success rate")
fig
Distance to minimizer vs. iterations
Lower is better. Shows "close but not converged" cases that the pass/fail plots hide.
plot_curves(
Dict(l => Float64.(RUN_LENGTH) for l in LABELS),
Dict(l => results[l].distance_to_minimizer for l in LABELS);
xlabel = "Iterations", ylabel = "Mean distance to minimizer",
xlims = (1, maximum(RUN_LENGTH)), ylims = (0, 5), best_is_high = false
)
Relative runtime
Median time to success, relative to Nelder-Mead, log scale. Uses only successful runs, so it reads as "when this optimizer solves a problem, how long does it take"; read it together with the wall-clock plot, which shows how often it solves one at all.
med(l) = (v = filter(isfinite, tts[l]); isempty(v) ? NaN : median(v))
rt = [med(l) for l in LABELS]
rt ./= med("NelderMead")
fig = Figure(size = (1050, 520))
ax = Axis(
fig[1, 1]; yscale = log10, ylabel = "Median time to success relative to Nelder-Mead",
xticks = (1:length(LABELS), LABELS), xticklabelrotation = π / 4
)
barplot!(ax, 1:length(LABELS), rt)
fig
Appendix
These benchmarks are a part of the SciMLBenchmarks.jl repository, found at: https://github.com/SciML/SciMLBenchmarks.jl. For more information on high-performance scientific machine learning, check out the SciML Open Source Software Organization https://sciml.ai.
To locally run this benchmark, do the following commands:
using SciMLBenchmarks
SciMLBenchmarks.weave_file("benchmarks/PSOGlobalOptimization","pso_global_optimizers.jmd")Computer Information:
Julia Version 1.12.7
Commit 6d172b025e4 (2026-08-15 08:05 UTC)
Build Info:
Official https://julialang.org release
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: 128 × AMD EPYC 9354 32-Core Processor
WORD_SIZE: 64
LLVM: libLLVM-18.1.7 (ORCJIT, znver4)
GC: Built with stock GC
Threads: 58 default, 1 interactive, 58 GC (on 58 virtual cores)
Environment:
JULIA_CPU_THREADS = 58
JULIA_NUM_PRECOMPILE_TASKS = 58
JULIA_NUM_THREADS = auto
JULIA_PYTHONCALL_EXE = /home/runner/_work/SciMLBenchmarks.jl/SciMLBenchmarks.jl/benchmarks/PSOGlobalOptimization/.CondaPkg/.pixi/envs/default/bin/python
Package Information:
Status `~/_work/SciMLBenchmarks.jl/SciMLBenchmarks.jl/benchmarks/PSOGlobalOptimization/Project.toml`
[4552ee2b] BlackBoxOptimizationBenchmarking v2.1.0
⌅ [052768ef] CUDA v5.11.3
⌃ [13f3f980] CairoMakie v0.15.13
⌃ [f6369f11] ForwardDiff v1.4.5
[63c18a36] KernelAbstractions v0.9.42
[c03570c3] Memoize v0.4.4
⌃ [7f7a1694] Optimization v5.7.1
⌃ [3e6eede4] OptimizationBBO v0.4.11
⌃ [cb963754] OptimizationEvolutionary v0.4.13
⌃ [3aafef2f] OptimizationMetaheuristics v0.3.11
⌃ [4e6fcdb7] OptimizationNLopt v0.3.16
⌃ [36348300] OptimizationOptimJL v0.4.19
⌃ [cce07bd8] OptimizationSciPy v0.4.10
⌃ [ab63da0c] ParallelParticleSwarms v1.6.0
[31c91b34] SciMLBenchmarks v0.2.1 [loaded: `/home/runner/_work/SciMLBenchmarks.jl/SciMLBenchmarks.jl/src/SciMLBenchmarks.jl` (v0.2.1) expected `/home/runner/.julia/packages/SciMLBenchmarks/ceJyd/src/SciMLBenchmarks.jl` (v0.2.1)]
⌃ [90137ffa] StaticArrays v1.9.19
[44d3d7a6] Weave v0.10.12
Info Packages marked with ⌃ and ⌅ have new versions available. Those with ⌃ may be upgradable, but those with ⌅ are restricted by compatibility constraints from upgrading. To see why use `status --outdated`And the full manifest:
Status `~/_work/SciMLBenchmarks.jl/SciMLBenchmarks.jl/benchmarks/PSOGlobalOptimization/Manifest.toml`
[47edcb42] ADTypes v1.24.0
⌃ [14f7f29c] AMD v0.5.3
[621f4979] AbstractFFTs v1.5.0
[1520ce14] AbstractTrees v0.4.5
[7d9f7c33] Accessors v0.1.45
⌃ [79e6a3ab] Adapt v4.7.0
[35492f91] AdaptivePredicates v1.2.0
[66dad0bd] AliasTables v1.1.3
[27a7e980] Animations v0.4.2
⌃ [4fba245c] ArrayInterface v7.30.0
⌃ [a9b6321e] Atomix v1.1.3
[67c07d97] Automa v1.2.0
[13072b0f] AxisAlgorithms v1.1.0
[39de3d68] AxisArrays v0.4.8
⌃ [ab4f0b2a] BFloat16s v0.6.1
[18cc8868] BaseDirs v1.4.0
[a134a8b2] BlackBoxOptim v0.6.12
[4552ee2b] BlackBoxOptimizationBenchmarking v2.1.0
⌃ [70df07ce] BracketingNonlinearSolve v1.12.5
[fa961155] CEnum v0.5.0
[96374032] CRlibm v1.0.2
⌅ [052768ef] CUDA v5.11.3
⌃ [1af6417a] CUDA_Runtime_Discovery v2.1.0
[159f3aea] Cairo v1.1.1
⌃ [13f3f980] CairoMakie v0.15.13
[d360d2e6] ChainRulesCore v1.26.1
[6b39b394] CodecZstd v0.8.7
[a2cac450] ColorBrewer v0.4.2
[35d6a980] ColorSchemes v3.31.0
⌃ [3da002f7] ColorTypes v0.12.1
[c3611d14] ColorVectorSpace v0.11.0
⌃ [5ae59095] Colors v0.13.1
[861a8166] Combinatorics v1.1.0
[38540f10] CommonSolve v0.2.14
[bbf7d656] CommonSubexpressions v0.3.1
[34da2185] Compat v4.18.1
[a33af91c] CompositionsBase v0.1.2
[95dc2771] ComputePipeline v0.1.8
[2569d6c7] ConcreteStructs v0.2.8
⌃ [992eb4ea] CondaPkg v0.2.33
[88cd18e8] ConsoleProgressMonitor v0.1.2
[187b0558] ConstructionBase v1.6.0
[d38c429a] Contour v0.6.3
[b7a15901] CoreMath v0.1.0
[a8cc5b0e] Crayons v4.2.0
[9a962f9c] DataAPI v1.16.0
[864edb3b] DataStructures v0.19.6
[e2d170a0] DataValueInterfaces v1.0.0
⌃ [927a84f5] DelaunayTriangulation v1.6.6
[8bb1440f] DelimitedFiles v1.9.1
⌃ [2b5f629d] DiffEqBase v7.18.2
⌃ [071ae1c0] DiffEqGPU v3.18.0
[163ba53b] DiffResults v1.1.0
[b552c78f] DiffRules v1.16.0
[a0c0ee7d] DifferentiationInterface v0.7.21
[b4f34e82] Distances v0.10.12
[31c24e10] Distributions v0.25.131
[ffbed154] DocStringExtensions v0.9.5
[4e289a0a] EnumX v1.0.7
⌃ [7da242da] Enzyme v0.13.199
[f151be2c] EnzymeCore v0.8.21
⌅ [86b6b26d] Evolutionary v0.11.9
[429591f6] ExactPredicates v2.2.9
[e2ba6199] ExprTools v0.1.11
[b86e33f2] FFTA v0.3.1
[7034ab61] FastBroadcast v1.4.0
[9aa1b823] FastClosures v0.3.2
[a4df4552] FastPower v1.5.0
[5789e2e9] FileIO v1.20.0
[8fc22ac5] FilePaths v0.9.0
[48062228] FilePathsBase v0.9.24
⌃ [1a297f60] FillArrays v1.17.0
⌃ [64ca27bc] FindFirstFunctions v3.2.1
[6a86dc24] FiniteDiff v2.33.0
⌅ [53c48c17] FixedPointNumbers v0.8.6
[1fa38f19] Format v1.3.7
⌃ [f6369f11] ForwardDiff v1.4.5
[b38be410] FreeType v4.1.1
[663a7486] FreeTypeAbstraction v0.10.8
[069b7b12] FunctionWrappers v1.1.3
[77dc65aa] FunctionWrappersWrappers v1.13.0
⌃ [0c68f7d7] GPUArrays v11.5.13
⌅ [46192b85] GPUArraysCore v0.2.0
⌅ [61eb1bfa] GPUCompiler v1.17.1
⌅ [096a3bc2] GPUToolbox v1.1.1
⌃ [a0844989] Gamma v1.1.0
⌃ [5c1252a2] GeometryBasics v0.5.11
[a2bd30eb] Graphics v1.1.3
⌃ [3955a311] GridLayoutBase v0.11.2
[076d061b] HashArrayMappedTries v0.2.0
⌅ [eafb193a] Highlights v0.5.3
[34004b35] HypergeometricFunctions v0.3.30
[2803e5a7] ImageAxes v0.6.12
[c817782e] ImageBase v0.1.7
[a09fc81d] ImageCore v0.10.5
⌃ [82e4d734] ImageIO v0.6.9
[bc367c6b] ImageMetadata v0.9.10
[9b13fd28] IndirectArrays v1.0.0
[d25df0c9] Inflate v0.1.5
[18e54dd8] IntegerMathUtils v0.1.4
[a98d9a8b] Interpolations v0.16.3
⌃ [d1acc4aa] IntervalArithmetic v1.0.11
[8197267c] IntervalSets v0.7.14
[3587e190] InverseFunctions v0.1.17
[92d709cd] IrrationalConstants v0.2.6
[f1662d9f] Isoband v0.1.1
[c8e1da08] IterTools v1.10.0
[82899510] IteratorInterfaceExtensions v1.0.0
[692b3bcd] JLLWrappers v1.8.0
⌅ [358108f5] JMcDM v0.7.24
⌅ [682c06a0] JSON v0.21.4
[0f8b85d8] JSON3 v1.14.3
[b835a17e] JpegTurbo v0.1.6
[63c18a36] KernelAbstractions v0.9.42
[5ab0869b] KernelDensity v0.6.12
⌃ [ba0b0d4f] Krylov v0.10.9
⌃ [2faa5264] LHLFactorization v2.2.0
⌃ [929cbde3] LLVM v9.13.0
[8b046642] LLVMLoopInfo v1.0.0
[b964fa9f] LaTeXStrings v1.4.1
⌅ [73f95e8e] LatticeRules v0.0.1
[8cdb02fc] LazyModules v0.3.1
[1d6d02ad] LeftChildRightSiblingTrees v0.3.0
⌃ [87fe0de2] LineSearch v0.1.16
⌃ [d3d80556] LineSearches v7.7.1
⌃ [7ed4a6bd] LinearSolve v5.13.0
⌃ [2ab3a3ac] LogExpFunctions v0.3.29
[e6f89c97] LoggingExtras v1.2.0
[1914dd2f] MacroTools v0.5.16
⌅ [ee78f7c6] Makie v0.24.13
[dbb5928d] MappedArrays v0.4.3
[0a4f8689] MathTeXEngine v0.6.9
[bb5d69b7] MaybeInplace v0.1.8
[c03570c3] Memoize v0.4.4
[bcdb8e00] Metaheuristics v3.5.0
[0b3b1443] MicroMamba v0.1.15
[e1d29d7a] Missings v1.2.0
[e94cdb99] MosaicViews v0.3.4
[46d2c3a1] MuladdMacro v0.2.7
⌃ [ffc61752] Mustache v1.0.21 [loaded: v1.1.0]
[d41bc354] NLSolversBase v8.0.1
[76087f3c] NLopt v1.2.1
[5da4648a] NVTX v1.0.3
[77ba4419] NaNMath v1.1.4
[f09324ee] Netpbm v1.1.1
⌃ [be0214bd] NonlinearSolveBase v2.47.0
[d8793406] ObjectFile v0.5.1
[510215fc] Observables v0.5.5
[6fe1bfb0] OffsetArrays v1.17.0
[52e1d378] OpenEXR v0.3.3
⌃ [429524aa] Optim v2.2.2
⌃ [7f7a1694] Optimization v5.7.1
⌃ [3e6eede4] OptimizationBBO v0.4.11
⌃ [bca83a33] OptimizationBase v5.4.0
⌃ [cb963754] OptimizationEvolutionary v0.4.13
⌃ [3aafef2f] OptimizationMetaheuristics v0.3.11
⌃ [4e6fcdb7] OptimizationNLopt v0.3.16
⌃ [36348300] OptimizationOptimJL v0.4.19
⌃ [cce07bd8] OptimizationSciPy v0.4.10
[bac558e1] OrderedCollections v2.0.1
[90014a1f] PDMats v0.11.41
[f57f5aa1] PNGFiles v0.4.5
[19eb6ba3] Packing v0.5.1
[5432bcbf] PaddedViews v0.5.12
⌃ [ab63da0c] ParallelParticleSwarms v1.6.0
[d96e819e] Parameters v0.13.1
⌅ [69de0a69] Parsers v2.8.7 [loaded: v2.8.8]
[fa939f87] Pidfile v1.3.0
[eebad327] PkgVersion v0.3.3
⌃ [995b91a9] PlotUtils v1.4.4
[647866c9] PolygonOps v0.1.2
[85a6dd25] PositiveFactorizations v0.2.4
⌃ [d236fae5] PreallocationTools v1.6.0
[aea7be01] PrecompileTools v1.3.4
⌃ [21216c6a] Preferences v1.5.2 [loaded: v1.6.0]
[08abe8d2] PrettyTables v3.4.8
[27ebfcd6] Primes v0.5.7
[33c8b6b6] ProgressLogging v0.1.6
[92933f4c] ProgressMeter v1.11.0
[43287f4e] PtrArrays v1.4.0
⌃ [0c0d3e7f] PureKLU v1.4.1
⌃ [6099a3de] PythonCall v0.9.35
[4b34888f] QOI v1.0.2
[1fd47b50] QuadGK v2.11.3
⌃ [8a4e6c94] QuasiMonteCarlo v0.4.1
[74087812] Random123 v1.7.1
[e6cf234a] RandomNumbers v1.6.0
[b3c3ace0] RangeArrays v0.3.2
[c84ed2f1] Ratios v0.4.5
[3cdcf5f2] RecipesBase v1.3.4
⌃ [731186ca] RecursiveArrayTools v4.5.0
[189a3867] Reexport v1.2.2
[05181044] RelocatableFolders v1.0.1
[ae029012] Requires v1.3.1
[9fe22ead] RespecializeParams v1.3.0
[79098fc4] Rmath v0.9.0
⌃ [f2b01f46] Roots v3.0.7
[5eaf0fd0] RoundingEmulator v0.2.1
⌃ [7e49a35a] RuntimeGeneratedFunctions v0.5.25
[fdea26ae] SIMD v3.7.2
⌃ [0bca4576] SciMLBase v3.49.2
[31c91b34] SciMLBenchmarks v0.2.1 [loaded: `/home/runner/_work/SciMLBenchmarks.jl/SciMLBenchmarks.jl/src/SciMLBenchmarks.jl` (v0.2.1) expected `/home/runner/.julia/packages/SciMLBenchmarks/ceJyd/src/SciMLBenchmarks.jl` (v0.2.1)]
⌃ [19f34311] SciMLJacobianOperators v0.1.17
[a6db7da4] SciMLLogging v2.1.0
⌃ [c0aeaf25] SciMLOperators v1.29.0
[431bcebd] SciMLPublic v1.3.0
⌃ [53ae85a6] SciMLStructures v1.10.4
[7e506255] ScopedValues v1.6.2
[6c6a2e73] Scratch v1.3.0
[eb7571c6] SearchSpaces v0.2.0
[efcf1570] Setfield v1.1.2
⌃ [65257c39] ShaderAbstractions v0.5.0
[73760f76] SignedDistanceFields v0.4.1
⌃ [05bca326] SimpleDiffEq v1.17.0
⌃ [727e6d20] SimpleNonlinearSolve v2.14.0
⌃ [510db2f7] SimpleOptimization v2.0.0
[699a6c99] SimpleTraits v0.9.6
[45858cf5] Sixel v0.1.5
[66db9d55] SnoopPrecompile v1.0.3
[ed01d8cd] Sobol v1.5.0
[a2af1166] SortingAlgorithms v1.2.3
⌃ [a57abbd0] SparseColumnPivotedQR v2.1.7
⌃ [9f842d2f] SparseConnectivityTracer v1.2.2
⌃ [0a514795] SparseMatrixColorings v0.4.26
[276daf66] SpecialFunctions v2.9.0
[860ef19b] StableRNGs v1.0.4
[cae243ae] StackViews v0.1.2
⌃ [90137ffa] StaticArrays v1.9.19
[1e83bf80] StaticArraysCore v1.4.4
⌃ [10745b16] Statistics v1.11.1
[82ae8749] StatsAPI v1.8.0
⌃ [2913bbd2] StatsBase v0.34.12
[4c63d2b9] StatsFuns v2.2.1
[69024149] StringEncodings v0.3.7
⌅ [892a3eda] StringManipulation v0.5.0
[09ab397b] StructArrays v0.7.3
[53d494c1] StructIO v0.3.1
[856f2bd8] StructTypes v1.11.0
[2efcf032] SymbolicIndexingInterface v0.3.55
[3783bdb8] TableTraits v1.0.1
⌃ [bd369af6] Tables v1.13.0 [loaded: v1.14.0]
[62fd8b95] TensorCore v0.1.1
[5d786b92] TerminalLoggers v0.1.8
[731e570b] TiffImages v0.11.9
⌃ [a759f4b9] TimerOutputs v1.2.0
[e689c965] Tracy v0.1.6
[3bb67fe8] TranscodingStreams v0.11.3
[981d1d27] TriplotBase v0.1.0
[781d530d] TruncatedStacktraces v1.4.0
[3a884ed6] UnPack v1.0.2
[1cfade01] UnicodeFun v0.4.1
⌃ [1986cc42] Unitful v1.28.0
[013be700] UnsafeAtomics v0.3.2
[e17b2a0c] UnsafePointers v1.0.0
[44d3d7a6] Weave v0.10.12
[e3aaa7dc] WebP v0.1.3
[efce3f68] WoodburyMatrices v1.1.0
⌃ [ddb6d928] YAML v0.4.16 [loaded: v0.4.17]
[700de1a5] ZygoteRules v0.2.8
[6e34b625] Bzip2_jll v1.0.9+0
[4e9b3aee] CRlibm_jll v1.0.1+0
⌅ [d1e2174e] CUDA_Compiler_jll v0.4.4+1
⌃ [4ee394cb] CUDA_Driver_jll v13.3.1+0
⌅ [76a88914] CUDA_Runtime_jll v0.21.0+1
[83423d85] Cairo_jll v1.18.7+0
[a38c48d9] CoreMath_jll v0.1.0+0
⌅ [5ae413db] EarCut_jll v2.2.4+0
⌅ [7cc45869] Enzyme_jll v0.0.290+0
⌃ [2e619515] Expat_jll v2.8.3+0
⌅ [b22a6f82] FFMPEG_jll v8.1.2+0
[a3f928ae] Fontconfig_jll v2.17.1+0
[d7e528f0] FreeType2_jll v2.14.3+1
[559328eb] FriBidi_jll v1.0.17+0
⌅ [b0724c58] GettextRuntime_jll v0.22.4+0
⌅ [59f7168a] Giflib_jll v5.2.3+0
[7746bdde] Glib_jll v2.88.3+0
[3b182d85] Graphite2_jll v1.3.16+0
⌅ [2e76f6c2] HarfBuzz_jll v8.5.1+0
[905a6f67] Imath_jll v3.2.2+0
[1d5cc7b8] IntelOpenMP_jll v2025.2.0+0
[aacddb02] JpegTurbo_jll v3.2.0+1
[9c1d0b0a] JuliaNVTXCallbacks_jll v0.2.1+0
[c1c5ebd0] LAME_jll v3.100.3+0
⌃ [88015f11] LERC_jll v4.1.0+0
⌅ [dad2f222] LLVMExtra_jll v0.0.46+0
⌃ [1d63c593] LLVMOpenMP_jll v22.1.7+0
[ad6e5548] LibTracyClient_jll v0.13.1+0
⌅ [e9f186c6] Libffi_jll v3.4.7+0
[7e76a0d4] Libglvnd_jll v1.7.1+1
[94ce4f54] Libiconv_jll v1.18.0+0
[4b2f31a3] Libmount_jll v2.42.0+0
[89763e89] Libtiff_jll v4.7.3+0
[38a345b3] Libuuid_jll v2.42.0+0
[856f044c] MKL_jll v2025.2.0+0
[079eb43e] NLopt_jll v2.11.0+0
[e98f9f5b] NVTX_jll v3.2.2+0
[e7412a2a] Ogg_jll v1.3.6+0
[6cdc7f73] OpenBLASConsistentFPCSR_jll v0.3.34+0
⌃ [18a262bb] OpenEXR_jll v3.4.14+0
[efe28fd5] OpenSpecFun_jll v0.5.6+0
[91d4177d] Opus_jll v1.6.1+0
⌃ [36c8627f] Pango_jll v1.58.0+0
[30392449] Pixman_jll v0.46.4+0
[f50d1b31] Rmath_jll v0.5.2+0
⌃ [ffd25f8a] XZ_jll v5.8.3+0
[4f6342f7] Xorg_libX11_jll v1.8.13+0
[0c0b7dd1] Xorg_libXau_jll v1.0.13+0
[a3789734] Xorg_libXdmcp_jll v1.1.6+0
[1082639a] Xorg_libXext_jll v1.3.8+0
[d091e8ba] Xorg_libXfixes_jll v6.0.2+0
[ea2f1a96] Xorg_libXrender_jll v0.9.12+0
[a65dc6b1] Xorg_libpciaccess_jll v0.19.0+0
[c7cfdc94] Xorg_libxcb_jll v1.17.1+0
[c5fb5394] Xorg_xtrans_jll v1.6.0+0
[3161d3a3] Zstd_jll v1.5.7+1
[1e29f10c] demumble_jll v1.3.0+0
[9a68df92] isoband_jll v0.2.3+0
⌃ [a4ae2306] libaom_jll v3.14.1+0
⌃ [0ac62f75] libass_jll v0.17.4+0
[8e53e030] libdrm_jll v2.4.134+0
[f638f0a6] libfdk_aac_jll v2.0.4+0
[b53b4c65] libpng_jll v1.6.58+0
[075b6546] libsixel_jll v1.10.5+0
[9a156e7d] libva_jll v2.23.0+0
[f27f6e37] libvorbis_jll v1.3.8+0
⌃ [c5f90fcd] libwebp_jll v1.6.0+0
[f8abcde7] micromamba_jll v2.3.1+0
[1317d2d5] oneTBB_jll v2022.3.0+0
[4d7b5844] pixi_jll v0.76.2+0
⌅ [1270edf5] x264_jll v10164.0.1+0
[dfaa095f] x265_jll v4.1.0+0
[0dad84c5] ArgTools v1.1.2
[56f22d72] Artifacts v1.11.0
[2a0f44e3] Base64 v1.11.0
[8bf52ea8] CRC32c v1.11.0
[ade2ca70] Dates v1.11.0
[8ba89e20] Distributed v1.11.0
[f43a241f] Downloads v1.7.0
[7b1f6079] FileWatching v1.11.0
[9fa8497b] Future v1.11.0
[b77e0a4c] InteractiveUtils v1.11.0
[ac6e5ff7] JuliaSyntaxHighlighting v1.12.0
[4af54fe1] LazyArtifacts v1.11.0
[b27032c2] LibCURL v0.6.4
[76f85450] LibGit2 v1.11.0
[8f399da3] Libdl v1.11.0
[37e2e46d] LinearAlgebra v1.12.0
[56ddb016] Logging v1.11.0
[d6f4376e] Markdown v1.11.0
[a63ad114] Mmap v1.11.0
[ca575930] NetworkOptions v1.3.0
[44cfe95a] Pkg v1.12.1
[de0858da] Printf v1.11.0
[3fa0cd96] REPL v1.11.0
[9a3f8284] Random v1.11.0
[ea8e919c] SHA v0.7.0
[9e88b42a] Serialization v1.11.0
[1a1011a3] SharedArrays v1.11.0
[6462fe0b] Sockets v1.11.0
[2f01184e] SparseArrays v1.12.0
[f489334b] StyledStrings v1.11.0
[4607b0f0] SuiteSparse
[fa267f1f] TOML v1.0.3
[a4e569a6] Tar v1.10.0
[8dfed614] Test v1.11.0
[cf7118a7] UUIDs v1.11.0
[4ec0a83e] Unicode v1.11.0
[e66e0078] CompilerSupportLibraries_jll v1.3.1+2
[deac9b47] LibCURL_jll v8.15.0+0
[e37daf67] LibGit2_jll v1.9.0+0
[29816b5a] LibSSH2_jll v1.11.3+1
[14a3606d] MozillaCACerts_jll v2025.11.4
[4536629a] OpenBLAS_jll v0.3.29+0
[05823500] OpenLibm_jll v0.8.7+0
[458c3c95] OpenSSL_jll v3.5.6+0
[efcefdf7] PCRE2_jll v10.44.0+1
[bea87d4a] SuiteSparse_jll v7.8.3+2
[83775a58] Zlib_jll v1.3.1+2
[8e850b90] libblastrampoline_jll v5.15.0+0
[8e850ede] nghttp2_jll v1.64.0+1
[3f19e933] p7zip_jll v17.7.0+0
Info Packages marked with ⌃ and ⌅ have new versions available. Those with ⌃ may be upgradable, but those with ⌅ are restricted by compatibility constraints from upgrading. To see why use `status --outdated -m`