A minimal, differentiable Frank-Wolfe solver for constrained convex optimization in Julia.
Named in honor of Marguerite Frank (1927--2024), co-inventor of the Frank-Wolfe algorithm (1956).
Finds parameterized solutions to constrained convex programs of the form
where
Marguerite.jl is built for simple and fast bilevel optimization, meaning optimization programs that appear as
Marguerite implements implicit differentiation through the KKT conditions of the inner problem, using the active constraint structure of each oracle to build efficient pullbacks. The solver, differentiation, and bilevel interface share a single solve entry point.
using Marguerite, LinearAlgebra
# -- Constrained optimization ---------------------
Q = [4.0 1.0; 1.0 2.0]; c = [-3.0, -1.0]
f(x) = 0.5 * dot(x, Q * x) + dot(c, x)
∇f!(g, x) = (g .= Q * x .+ c)
x, result = solve(f, ProbSimplex(), [0.5, 0.5]; grad=∇f!)
# -- Bilevel optimization -------------------------
x_target = [0.7, 0.3]; θ = zeros(2); η = 0.1
inner(x, θ) = 0.5 * dot(x, x) - dot(θ, x)
outer(x) = sum((x .- x_target).^2)
x_curr = [0.5, 0.5]
for _ in 1:50
x, dθ, _ = bilevel_solve(outer, inner, ProbSimplex(),
x_curr, θ)
x_curr .= x
θ .-= η .* dθ
end
println("x_curr = ", round.(x_curr; digits=3)) # x_curr ≈ x_targetOmit grad= for automatic differentiation via ForwardDiff.
- You have a constrained convex problem and a linear minimization oracle (LMO) for the constraint set
- You want differentiable optimization -- gradients through the solver via implicit differentiation
- You need projection-free optimization (simplex, knapsack, matroid, flow polytopes, etc.)
- You want bilevel optimization with constrained inner problems
- You value a simple, minimal API with zero-allocation inner loops
- Single entry point:
solve(f, lmo, x0; grad=∇f!, ...), with or without automatic gradients and differentiable parameters - Pre-allocated buffers for allocation-free inner loops (
@inboundshot paths) - Seven built-in oracles: simplex, probability simplex, knapsack, masked knapsack, box, weighted simplex, spectraplex
- Custom oracles: any
(v, g) -> vcallable for primal solves; differentiated custom oracles should also implementactive_set - Differentiable solve via
ChainRulesCore.rrulefor$\partial x^* / \partial \theta$ (implicit differentiation) - Bilevel optimization:
bilevel_solvebackpropagates through the solver to learn parameters of constrained problems
Other great packages in the Frank-Wolfe ecosystem:
- FrankWolfe.jl — comprehensive Frank-Wolfe toolbox by Besançon, Pokutta et al.
- DifferentiableFrankWolfe.jl — differentiable wrapper for FrankWolfe.jl
See the full documentation for tutorials, examples, and API reference.
Requires Julia 1.12+. Install directly from the repository:
using Pkg
Pkg.add(url="https://github.com/samtalki/Marguerite.jl")Run the default representative suite:
julia --project=. -e 'using Pkg; Pkg.test()'Run the exhaustive suite with the full differentiation, bilevel, and verification sweeps:
MARGUERITE_TEST_GROUP=all julia --project=. -e 'using Pkg; Pkg.test()'If you use Marguerite.jl in your research, please cite:
@software{talkington2026marguerite,
author = {Talkington, Samuel},
title = {Marguerite.jl: A Minimal, Differentiable Frank-Wolfe Solver},
year = {2026},
url = {https://github.com/samtalki/Marguerite.jl},
version = {0.2.0}
}- M. Frank & P. Wolfe, "An algorithm for quadratic programming," Naval Research Logistics, 1956.
- A. Carderera, M. Besançon & S. Pokutta, "Scalable Frank-Wolfe on Generalized Self-concordant Functions via Simple Steps," SIAM J. Optim., 2024.
- S. Lacoste-Julien & M. Jaggi, "On the Global Linear Convergence of Frank-Wolfe Optimization Variants," NeurIPS, 2015.
- A. Palmieri, F. Rinaldi, S. Salzo & S. Venturini, "Iteration Complexity of Frank-Wolfe and Its Variants for Bilevel Optimization," 2026.
