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 @@ -28,6 +28,12 @@ function demo_solver(f, nls, sol, h, χ, suffix = "l0-linf")
LMTR_out = LMTR(nls, h, χ, options, x0 = f.meta.x0)
@info "LMTR relative error" norm(LMTR_out.solution - sol) / norm(sol)
plot_bpdn(LMTR_out, sol, "constr-lmtr-r2-$(suffix)")

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

function demo_bpdn_constr(compound = 1)
Expand Down
17 changes: 13 additions & 4 deletions src/LM_alg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and σ > 0 is a regularization parameter.
* `subsolver_logger::AbstractLogger`: a logger to pass to the subproblem solver
* `subsolver`: the procedure used to compute a step (`PG` or `R2`)
* `subsolver_options::ROSolverOptions`: default options to pass to the subsolver.
* `selected::AbstractVector{<:Integer}`: (default `1:f.meta.nvar`).

### Return values

Expand All @@ -45,6 +46,7 @@ function LM(
subsolver_logger::Logging.AbstractLogger = Logging.NullLogger(),
subsolver = R2,
subsolver_options = ROSolverOptions(),
selected::AbstractVector{<:Integer} = 1:(nls.meta.nvar),
) where {H}
start_time = time()
elapsed_time = 0.0
Expand All @@ -60,6 +62,12 @@ function LM(
θ = options.θ
σmin = options.σmin

local l_bound, u_bound
if has_bounds(nls)
l_bound = nls.meta.lvar
u_bound = nls.meta.uvar
end

if verbose == 0
ptf = Inf
elseif verbose == 1
Expand All @@ -73,16 +81,16 @@ function LM(
# initialize parameters
σk = max(1 / options.ν, σmin)
xk = copy(x0)
hk = h(xk)
hk = h(xk[selected])
if hk == Inf
verbose > 0 && @info "LM: 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 "LM: found point where h has value" hk
end
hk == -Inf && error("nonsmooth term is not proper")
ψ = shifted(h, xk)
ψ = has_bounds(nls) ? shifted(h, xk, l_bound - xk, u_bound - xk, selected) : shifted(h, xk)

xkn = similar(xk)

Expand Down Expand Up @@ -179,7 +187,7 @@ function LM(
xkn .= xk .+ s
residual!(nls, xkn, Fkn)
fkn = dot(Fkn, Fkn) / 2
hkn = h(xkn)
hkn = h(xkn[selected])
hkn == -Inf && error("nonsmooth term is not proper")
mks = mk(s)
ξ = fk + hk - mks + max(1, abs(hk)) * 10 * eps()
Expand All @@ -205,6 +213,7 @@ function LM(

if η1 ≤ ρk < Inf
xk .= xkn
has_bounds(nls) && set_bounds!(ψ, l_bound - xk, u_bound - xk)

# update functions
Fk .= Fkn
Expand Down
2 changes: 1 addition & 1 deletion test/test_bounds.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ for (mod, mod_name) ∈ ((x -> x, "exact"), (LSR1Model, "lsr1"), (LBFGSModel, "l
end

for (h, h_name) ∈ ((NormL0(λ), "l0"), (NormL1(λ), "l1"))
for solver_sym ∈ (:LMTR,)
for solver_sym ∈ (:LMTR, :LM)
solver_name = string(solver_sym)
solver = eval(solver_sym)
@testset "bpdn-with-bounds-ls-$(solver_name)-$(h_name)" begin
Expand Down