diff --git a/src/linesearch.jl b/src/linesearch.jl index 70c4788ea..cc52f175e 100644 --- a/src/linesearch.jl +++ b/src/linesearch.jl @@ -26,15 +26,15 @@ build_linesearch_workspace(::LineSearchMethod, x, gradient) = nothing """ Computes step size: `l/(l + t)` at iteration `t`, given `l > 0`. -See: +Using `l ≥ 4` is advised only for strongly convex sets, see: > Acceleration of Frank-Wolfe Algorithms with Open-Loop Step-Sizes, Wirth, Kerdreux, Pokutta, 2023. - """ struct Agnostic{T<:Real} <: LineSearchMethod l::Int end Agnostic() = Agnostic{Float64}(2) +Agnostic(l::Int) = Agnostic{Float64}(l) Agnostic{T}() where {T} = Agnostic{T}(2) diff --git a/test/trajectory_tests/open_loop_parametric.jl b/test/trajectory_tests/open_loop_parametric.jl new file mode 100644 index 000000000..83c209e21 --- /dev/null +++ b/test/trajectory_tests/open_loop_parametric.jl @@ -0,0 +1,91 @@ +using FrankWolfe + +using Test +using LinearAlgebra + +@testset "Open-loop FW on polytope" begin + n = Int(1e2) + k = Int(1e4) + + xp = ones(n) + f(x) = norm(x - xp)^2 + function grad!(storage, x) + @. storage = 2 * (x - xp) + end + + lmo = FrankWolfe.KSparseLMO(40, 1.0) + + x0 = FrankWolfe.compute_extreme_point(lmo, zeros(n)) + + res_2 = FrankWolfe.frank_wolfe( + f, + grad!, + lmo, + copy(x0), + max_iteration=k, + line_search=FrankWolfe.Agnostic(2), + print_iter=k / 10, + epsilon=1e-5, + verbose=true, + trajectory=true, + ) + + res_10 = FrankWolfe.frank_wolfe( + f, + grad!, + lmo, + copy(x0), + max_iteration=k, + line_search=FrankWolfe.Agnostic(10), + print_iter=k / 10, + epsilon=1e-5, + verbose=true, + trajectory=true, + ) + + @test res_2[4] ≤ 0.004799839951985518 + @test res_10[4] ≤ 0.02399919272834694 + + # strongly convex set + xp2 = 10 * ones(n) + diag_term = 100 * rand(n) + covariance_matrix = LinearAlgebra.Diagonal(diag_term) + lmo2 = FrankWolfe.EllipsoidLMO(covariance_matrix) + + f2(x) = norm(x - xp2)^2 + function grad2!(storage, x) + @. storage = 2 * (x - xp2) + end + + x0 = FrankWolfe.compute_extreme_point(lmo2, randn(n)) + + res_2 = FrankWolfe.frank_wolfe( + f2, + grad2!, + lmo2, + copy(x0), + max_iteration=k, + line_search=FrankWolfe.Agnostic(2), + print_iter=k / 10, + epsilon=1e-5, + verbose=true, + trajectory=true, + ) + + res_10 = FrankWolfe.frank_wolfe( + f2, + grad2!, + lmo2, + copy(x0), + max_iteration=k, + line_search=FrankWolfe.Agnostic(10), + print_iter=k / 10, + epsilon=1e-5, + verbose=true, + trajectory=true, + ) + + @test length(res_10[end]) <= 8 + @test length(res_2[end]) <= 71 + +end