Skip to content
Open
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
3 changes: 1 addition & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
DataFrames = "1.6"
LinearAlgebra = "1.9, 1.10"
LinearOperators = "2.8"
Logging = "1.9"
Printf = "1.9, 1.10"
QRupdate = "1.0"
Random = "1.9, 1.10"
SparseArrays = "1.9, 1.10"
Logging = "1.9"
julia = "1.9, 1.10"

[extras]
Expand Down
42 changes: 27 additions & 15 deletions src/BPDual.jl
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ function bpdual(
# ------------------------------------------------------------------
m, n = size(A)


work = rand(n)
work2 = rand(n)
work3 = rand(n)
work4 = rand(n)
work5 = rand(m)

tracer = ASPTracer(
Int[], # iteration
Float64[], # lambda
Expand All @@ -110,8 +117,8 @@ function bpdual(
active = Vector{Int}([])
state = Vector{Int}(zeros(Int, n))
y = Vector{Float64}(zeros(Float64, m))
S = Matrix{Float64}(zeros(Float64, m, 0))
R = Matrix{Float64}(zeros(Float64, 0, 0))
S = Matrix{Float64}(zeros(Float64, m, n))
R = Matrix{Float64}(zeros(Float64, n, n))
end

if homotopy
Expand Down Expand Up @@ -171,6 +178,8 @@ function bpdual(
numtrim = 0
nprodA = 0
nprodAt = 0
cur_r_size = 0


# ------------------------------------------------------------------
# Cold/warm-start initialization.
Expand Down Expand Up @@ -211,25 +220,25 @@ function bpdual(
sL, sU = infeasibilities(bl, bu, z)
g = b - λ*y # Steepest-descent direction

if isempty(R)
if isempty(R[1:cur_r_size,1:cur_r_size])
condS = 1
else
rmin = minimum(diag(R))
rmax = maximum(diag(R))
rmin = minimum(diag(R[1:cur_r_size, 1:cur_r_size]))
rmax = maximum(diag(R[1:cur_r_size, 1:cur_r_size]))
condS = rmax / rmin
end

if condS > 1e+10
eFlag = :EXIT_SINGULAR_LS
# Pad x with enough zeros to make it compatible with S.
npad = size(S, 2) - size(x, 1)
npad = size(S[:, 1:cur_r_size], 2) - size(x, 1)
x = [x; zeros(npad)]
else
dx, dy = newtonstep(S, R, g, x, λ)
dx, dy = newtonstep(S[:,1:cur_r_size], R[1:cur_r_size, 1:cur_r_size], g, x, λ)
x .+= dx
end

r = b - S*x
r = b - S[:,1:cur_r_size]*x

# Print to log.
yNorm = norm(y, 2)
Expand Down Expand Up @@ -273,7 +282,7 @@ function bpdual(
@info "\nOptimal solution found. Trimming multipliers..."
end
g = b - λin*y
trimx(x, S, R, active, state, g, b, λ, feaTol, optTol, loglevel)
trimx(x, S[:, 1:cur_r_size], R[1:cur_r_size, 1:cur_r_size], active, state, g, b, λ, feaTol, optTol, loglevel)
numtrim = nact - length(active)
nact = length(active)
end
Expand All @@ -288,7 +297,7 @@ function bpdual(
p = q = 0

if homotopy
x, dy, dz, step, λ, p = htpynewlam(active, state, A, R, S, x, y, sL, sU, λ, lamFinal)
x, dy, dz, step, λ, p = htpynewlam(active, state, A, R[1:cur_r_size, 1:cur_r_size], S[:,1:cur_r_size], x, y, sL, sU, λ, lamFinal)
nprodAt += 1
else
if norm(dy, Inf) < eps()
Expand Down Expand Up @@ -339,8 +348,9 @@ function bpdual(
a = A * zerovec
nprodA += 1
zerovec[p] = 0
R = qraddcol(S, R, a)
S = [S a]
qraddcol!(S, R, a, cur_r_size, work, work2, work3, work4, work5) # Update R
cur_r_size +=1
# S = [S a]
push!(active, p)
push!(x, 0)
else
Expand All @@ -358,10 +368,12 @@ function bpdual(
_, qa = findmax(abs.(x .* dropa))
q = active[qa]
state[q] = 0
S = S[:, 1:nact .!= qa]
# S = S[:, 1:nact .!= qa]
deleteat!(active, qa)
deleteat!(x, qa)
R = qrdelcol(R, qa)
# R = qrdelcol(R, qa)
qrdelcol!(S, R, qa)
cur_r_size -=1
else
eFlag = :EXIT_OPTIMAL
end
Expand Down Expand Up @@ -390,4 +402,4 @@ function bpdual(
@info "Solution time (sec): $tottime"
end
return tracer
end
end
2 changes: 1 addition & 1 deletion src/helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,4 @@ function htpynewlam(active, state, A, R, S, x, y, s1, s2, λ, lamFinal)
end

return x, dy, dz, step, λ, p
end
end
53 changes: 33 additions & 20 deletions src/omp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,30 @@ function asp_omp(
optTol::Real = 1e-05,
gapTol::Real = 1e-06,
pivTol::Real = 1e-12,
actMax::Real = Inf)
actMax::Union{Real, Nothing} = nothing)

# Start the clock and size up the problem.
time0 = time()

z = A' * b

m = length(b)
n = length(z)

work = rand(size(A,2))
work2 = rand(size(A,2))
work3 = rand(size(A,2))
work4 = rand(size(A,2))
work5 = rand(size(A,1))

nprodA = 0
nprodAt = 1

# Initialize the tracer

tracer = OMPTracer(
Int[], # iteration
Float64[], # lambda
Vector{SparseVector{Float64}}() # now stores full sparse solutions
Int[],
Float64[],
Vector{SparseVector{Float64}}()
)

# Print log header.

if loglevel > 0
@info "-"^124
@info @sprintf("%-30s : %-10d %-30s : %-10.4e", "No. rows", m, "λ", λin)
Expand All @@ -76,6 +78,7 @@ function asp_omp(
@info "-"^124
end


# Initialize local variables.
EXIT_INFO = Dict(
:EXIT_OPTIMAL => "Optimal solution found -- full Newton step",
Expand All @@ -84,6 +87,7 @@ function asp_omp(
:EXIT_LAMBDA => "Reached minimum value of lambda",
:EXIT_RHS_ZERO => "b = 0. The solution is x = 0",
:EXIT_UNCONSTRAINED => "Unconstrained solution r = b is optimal",
:EXIT_ACTMAX => "Max no. of active constraints reached",
:EXIT_UNKNOWN => "unknown exit"
)

Expand All @@ -92,8 +96,8 @@ function asp_omp(
x = zeros(Float64, 0)
zerovec = zeros(Float64, n)
p = 0
cur_r_size = 0

# Quick exit if the RHS is zero.
if norm(b, Inf) == 0
r = zeros(m)
eFlag = :EXIT_RHS_ZERO
Expand All @@ -113,11 +117,17 @@ function asp_omp(
state = zeros(Int, n)
end
if R === nothing
R = Matrix{Float64}(undef, 0, 0)
R = Matrix{Float64}(undef, size(A,2), size(A,2))
S = Matrix{Float64}(undef, size(A,1), size(A,2))
end

@info @sprintf("%4s %8s %12s %12s %12s", "Itn", "Var", "λ", "rNorm", "xNorm")
if actMax === nothing
actMax = size(A, 2)
end

if loglevel>0
@info @sprintf("%4s %8s %12s %12s %12s", "Itn", "Var", "λ", "rNorm", "xNorm")
end

# Main loop.
while true
Expand All @@ -129,20 +139,22 @@ function asp_omp(
nprodAt += 1
zmax = norm(z, Inf)
else
x,y = csne(R, S, vec(b))
x,y = csne(R[1:cur_r_size, 1:cur_r_size], S[:,1:cur_r_size], vec(b))
if norm(x, Inf) > 1e12
eFlag = :EXIT_SINGULAR_LS
break
end

Sx = S * x
Sx = S[:,1:cur_r_size] * x
r = b - Sx
end

rNorm = norm(r, 2)
xNorm = norm(x, 1)

@info @sprintf("%4i %8i %12.5e %12.5e %12.5e", itn, p, zmax, rNorm, xNorm)
if loglevel>0
@info @sprintf("%4i %8i %12.5e %12.5e %12.5e", itn, p, zmax, rNorm, xNorm)
end

# Check exit conditions.
if eFlag != :EXIT_UNKNOWN
Expand All @@ -153,8 +165,10 @@ function asp_omp(
eFlag = :EXIT_OPTIMAL
elseif itn >= itnMax
eFlag = :EXIT_TOO_MANY_ITNS
elseif itn == actMax
eFlag = :EXIT_ACTMAX
end

if eFlag != :EXIT_UNKNOWN
break
end
Expand All @@ -180,14 +194,13 @@ function asp_omp(
nprodA += 1
zerovec[p] = 0

R = qraddcol(S, R, a) # Update R
S = hcat(S, a) # Expand S, active

qraddcol!(S, R, a, cur_r_size, work, work2, work3, work4, work5) # Update R
# S = hcat(S, a) # Expand S, active
cur_r_size +=1
push!(tracer.iteration, itn)
push!(tracer.lambda, zmax)
sparse_x_full = SparseVector(n, copy(active), copy(x))
push!(tracer.solution, copy(sparse_x_full))

push!(active, p)

end #while true
Expand Down
31 changes: 20 additions & 11 deletions test/test_bpdn.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

# ------------------------------------------------------------------
# Test Basis pursuit
# Test BPDN & OMP
# ------------------------------------------------------------------

using Test, LinearAlgebra, Random, SparseArrays, ActiveSetPursuit, LinearOperators

function test_bpdn()
function test_pursuits()
m = 600
n = 2560
k = 20
Expand All @@ -21,12 +21,16 @@ function test_bpdn()
b = A * x

# Solve the basis pursuit problem
tracer = asp_bpdn(A, b, 0.0, loglevel =0);
tracer_bpdn = asp_bpdn(A, b, 0.0, loglevel =0);
tracer_omp = asp_omp(A, b, 0.0, loglevel =0);
xx_bpdn, _ = tracer_bpdn[end]
xx_omp, _ = tracer_omp[end]

xx, λ = tracer[end]
pFeas = norm(A * xx - b, Inf) / max(1, norm(xx, Inf))
@test pFeas <= 1e-6
pFeas_bpdn = norm(A * xx_bpdn - b, Inf) / max(1, norm(xx_bpdn, Inf))
pFeas_omp = norm(A * xx_omp - b, Inf) / max(1, norm(xx_omp, Inf))

@test pFeas_bpdn <= 1e-6
@test pFeas_omp <= 1e-6
# ------------------------
# Linear operator
# ------------------------
Expand All @@ -35,15 +39,20 @@ function test_bpdn()
b_op = OP * x

# Solve the basis pursuit problem
tracer_op = asp_bpdn(OP, b_op, 0.0, loglevel =0);
tracer_op_bpdn = asp_bpdn(OP, b_op, 0.0, loglevel =0);
tracer_op_omp = asp_omp(OP, b_op, 0.0, loglevel =0);

xx_op, λ_op = tracer_op[end]
pFeas_op = norm(OP * xx_op - b_op, Inf) / max(1, norm(xx_op, Inf))
@test pFeas_op <= 1e-6
xx_op_bpdn, _ = tracer_op_bpdn[end]
xx_op_omp, _ = tracer_op_omp[end]

pFeas_bpdn_op = norm(OP * xx_op_bpdn - b_op, Inf) / max(1, norm(xx_op_bpdn, Inf))
pFeas_omp_op = norm(OP * xx_op_omp - b_op, Inf) / max(1, norm(xx_op_omp, Inf))
@test pFeas_bpdn_op <= 1e-6
@test pFeas_omp_op <= 1e-6
end

Random.seed!(1234)

for ntest = 1:10
test_bpdn()
test_pursuits()
end
2 changes: 1 addition & 1 deletion test/test_recover_decaying.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function test_recover_decaying()
bu = +ones(n)

# Solve the basis pursuit problem
tracer = asp_homotopy(A, b, min_lambda = 0.0, itnMax = 400, loglevel =0)
tracer = asp_homotopy(A, b, min_lambda = 0.0, actMax = 400, loglevel =0)
xs, λ = tracer[end]

cumulative_norm = cumsum(abs.(x[sortperm(abs.(x), rev=true)]))
Expand Down