Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions examples/demo-bpdn-constr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ function demo_solver(f, sol, h, χ, suffix = "l0-linf")
TR_out = TR(f, h, χ, options, x0 = f.meta.x0)
@info "TR relative error" norm(TR_out.solution - sol) / norm(sol)
plot_bpdn(TR_out, sol, "constr-tr-r2-$(suffix)")

@info " using R2 to solve with" h
reset!(f)
R2_out = R2(f, h, options, x0 = f.meta.x0)
@info "R2 relative error" norm(R2_out.solution - sol) / norm(sol)
plot_bpdn(R2_out, sol, "constr-r2-$(suffix)")
end

function demo_bpdn_constr(compound = 1)
Expand Down
9 changes: 7 additions & 2 deletions examples/demo-nnmf-constr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ include("plot-utils-nnmf.jl")
Random.seed!(1234)

function demo_solver(f, h, χ, selected, Avec, m, n, k, suffix = "l0-linf")
options = ROSolverOptions(ν = 1.0, β = 1e16, ϵa = 1e-6, ϵr = 1e-6, verbose = 10, maxIter = 500)
options = ROSolverOptions(ν = 1.0e-3, β = 1e16, ϵa = 1e-6, ϵr = 1e-6, verbose = 10, maxIter = 500)
@info " using TR to solve with" h χ
reset!(f)
TR_out = TR(f, h, χ, options, selected = selected)
plot_nnmf(TR_out, Avec, m, n, k, "tr-r2-$suffix")

@info " using R2 to solve with" h
reset!(f)
R2_out = R2(f, h, options, selected = selected)
plot_nnmf(R2_out, Avec, m, n, k, "r2-$suffix")
end

function demo_nnmf()
Expand All @@ -22,7 +27,7 @@ function demo_nnmf()
f = LSR1Model(model)
λ = norm(grad(model, rand(model.meta.nvar)), Inf) / 200
demo_solver(f, NormL0(λ), NormLinf(1.0), selected, A, m, n, k, "l0-linf")
λ = norm(grad(model, rand(model.meta.nvar)), Inf) / 10000
λ = norm(grad(model, rand(model.meta.nvar)), Inf) / 100000
demo_solver(f, NormL1(λ), NormLinf(1.0), selected, A, m, n, k, "l1-linf")
end

Expand Down
36 changes: 30 additions & 6 deletions src/R2_alg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ where φ(s ; xₖ) = f(xₖ) + ∇f(xₖ)ᵀs is the Taylor linear approximation
### Keyword Arguments

* `x0::AbstractVector`: an initial guess (in the first calling form: default = `nlp.meta.x0`)
* `selected::AbstractVector{<:Integer}`: (default `1:length(x0)`).

The objective and gradient of `nlp` will be accessed.

Expand All @@ -46,7 +47,15 @@ In the second form, instead of `nlp`, the user may pass in
function R2(nlp::AbstractNLPModel, args...; kwargs...)
kwargs_dict = Dict(kwargs...)
x0 = pop!(kwargs_dict, :x0, nlp.meta.x0)
xk, k, outdict = R2(x -> obj(nlp, x), (g, x) -> grad!(nlp, x, g), args..., x0; kwargs_dict...)
xk, k, outdict = R2(
x -> obj(nlp, x),
(g, x) -> grad!(nlp, x, g),
args...,
x0;
l_bound = nlp.meta.lvar,
u_bound = nlp.meta.uvar,
kwargs_dict...,
)
ξ = outdict[:ξ]
stats = GenericExecutionStats(nlp)
set_status!(stats, outdict[:status])
Expand All @@ -67,7 +76,9 @@ function R2(
∇f!::G,
h::H,
options::ROSolverOptions{R},
x0::AbstractVector{R},
x0::AbstractVector{R};
selected::AbstractVector{<:Integer} = 1:length(x0),
kwargs...,
) where {F <: Function, G <: Function, H, R <: Real}
start_time = time()
elapsed_time = 0.0
Expand All @@ -83,6 +94,18 @@ function R2(
ν = options.ν
γ = options.γ

local l_bound, u_bound
has_bnds = false
for (key, val) in kwargs
if key == :l_bound
l_bound = val
has_bnds = has_bnds || any(l_bound .!= R(-Inf))
elseif key == :u_bound
u_bound = val
has_bnds = has_bnds || any(u_bound .!= R(Inf))
end
end

if verbose == 0
ptf = Inf
elseif verbose == 1
Expand All @@ -95,19 +118,19 @@ function R2(

# initialize parameters
xk = copy(x0)
hk = h(xk)
hk = h(xk[selected])
if hk == Inf
verbose > 0 && @info "R2: finding initial guess where nonsmooth term is finite"
prox!(xk, h, x0, one(eltype(x0)))
hk = h(xk)
hk = h(xk[selected])
hk < Inf || error("prox computation must be erroneous")
verbose > 0 && @debug "R2: found point where h has value" hk
end
hk == -Inf && error("nonsmooth term is not proper")

xkn = similar(xk)
s = zero(xk)
ψ = shifted(h, xk)
ψ = has_bnds ? shifted(h, xk, l_bound - xk, u_bound - xk, selected) : shifted(h, xk)

Fobj_hist = zeros(maxIter)
Hobj_hist = zeros(maxIter)
Expand Down Expand Up @@ -158,7 +181,7 @@ function R2(
ξ > 0 || error("R2: prox-gradient step should produce a decrease but ξ = $(ξ)")
xkn .= xk .+ s
fkn = f(xkn)
hkn = h(xkn)
hkn = h(xkn[selected])
hkn == -Inf && error("nonsmooth term is not proper")

Δobj = (fk + hk) - (fkn + hkn) + max(1, abs(fk + hk)) * 10 * eps()
Expand All @@ -178,6 +201,7 @@ function R2(

if η1 ≤ ρk < Inf
xk .= xkn
has_bnds && set_bounds!(ψ, l_bound - xk, u_bound - xk)
fk = fkn
hk = hkn
∇f!(∇fk, xk)
Expand Down
2 changes: 1 addition & 1 deletion test/test_bounds.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
for (mod, mod_name) ∈ ((x -> x, "exact"), (LSR1Model, "lsr1"), (LBFGSModel, "lbfgs"))
for (h, h_name) ∈ ((NormL0(λ), "l0"), (NormL1(λ), "l1"))
for solver_sym ∈ (:TR,)
for solver_sym ∈ (:TR, :R2)
solver_sym == :TR && mod_name == "exact" && continue
solver_name = string(solver_sym)
solver = eval(solver_sym)
Expand Down