Skip to content

Commit

Permalink
Merge 29629f3 into 9922dd7
Browse files Browse the repository at this point in the history
  • Loading branch information
nantonel committed Feb 22, 2019
2 parents 9922dd7 + 29629f3 commit 1556b41
Show file tree
Hide file tree
Showing 16 changed files with 231 additions and 223 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -4,8 +4,8 @@ os:
- linux
- osx
julia:
- 0.7
- 1.0
- 1.1
- nightly
matrix:
allow_failures:
Expand Down
3 changes: 1 addition & 2 deletions appveyor.yml
@@ -1,7 +1,7 @@
environment:
matrix:
- julia_version: 0.7
- julia_version: 1
- julia_version: 1.1
- julia_version: nightly

platform:
Expand All @@ -10,7 +10,6 @@ platform:

matrix:
allow_failures:
- julia_version: 1
- julia_version: nightly

branches:
Expand Down
2 changes: 1 addition & 1 deletion src/ProximalAlgorithms.jl
@@ -1,7 +1,6 @@
module ProximalAlgorithms

using AbstractOperators
using AbstractOperators.BlockArrays
using ProximalOperators
using LinearAlgebra
using Printf
Expand All @@ -11,6 +10,7 @@ import Base: iterate
include("utilities/identity.jl")
include("utilities/zero.jl")
include("utilities/conjugate.jl")
include("utilities/tomove.jl")

abstract type ProximalAlgorithm{I,T} end

Expand Down
24 changes: 12 additions & 12 deletions src/algorithms/AsymmetricForwardBackwardAdjoint.jl
Expand Up @@ -5,7 +5,7 @@
# [2] Condat. "A primal–dual splitting method for convex optimization involving Lipschitzian, proximable and linear composite terms" Journal of Optimization Theory and Applications 158.2 (2013): 460-479.
# [3] Vũ. "A splitting algorithm for dual monotone inclusions involving cocoercive operators"" Advances in Computational Mathematics, 38(3), pp.667-681.

struct AFBAIterator{I <: Integer, R <: Real, T1 <: BlockArray, T2 <: BlockArray} <: ProximalAlgorithm{I, Tuple{T1, T2}}
struct AFBAIterator{I <: Integer, R <: Real, T1 <: AbstractArray, T2 <: AbstractArray} <: ProximalAlgorithm{I, Tuple{T1, T2}}
x::T1
y::T2
g
Expand Down Expand Up @@ -37,19 +37,19 @@ end
################################################################################
# Constructor(s)

function AFBAIterator(x0::T1, y0::T2; g=IndFree(), h=IndFree(), f=IndFree(), l=IndZero(), L=Identity(blocksize(x0)), theta=1, mu=1, lam=1, betaQ=0, betaR=0, gamma1=-1, gamma2=-1, maxit::I=10000, tol::R=1e-5, verbose=1, verbose_freq = 100) where {I, R, T1, T2}
x = blockcopy(x0)
xbar = blockcopy(x0)
y = blockcopy(y0)
ybar = blockcopy(y0)
gradf = blockcopy(x0)
gradl = blockcopy(y0)
FPR_x = blockcopy(x0)
function AFBAIterator(x0::T1, y0::T2; g=IndFree(), h=IndFree(), f=IndFree(), l=IndZero(), L=Identity(size(x0)), theta=1, mu=1, lam=1, betaQ=0, betaR=0, gamma1=-1, gamma2=-1, maxit::I=10000, tol::R=1e-5, verbose=1, verbose_freq = 100) where {I, R, T1, T2}
x = copy(x0)
xbar = copy(x0)
y = copy(y0)
ybar = copy(y0)
gradf = copy(x0)
gradl = copy(y0)
FPR_x = copy(x0)
FPR_x .= Inf
FPR_y = blockcopy(y0)
FPR_y = copy(y0)
FPR_y .= Inf
temp_x = blockcopy(x0)
temp_y = blockcopy(y0)
temp_x = copy(x0)
temp_y = copy(y0)
hconj = Conjugate(h)
lconj = Conjugate(l)

Expand Down
18 changes: 9 additions & 9 deletions src/algorithms/DouglasRachford.jl
Expand Up @@ -5,7 +5,7 @@
# [1] Eckstein, Bertsekas "On the Douglas-Rachford Splitting Method and the Proximal Point Algorithm for Maximal Monotone Operators*", Mathematical Programming, vol. 55, no. 1, pp. 293-318 (1989).
#

struct DRSIterator{I <: Integer, R <: Real, T <: BlockArray{R}} <: ProximalAlgorithm{I,T}
struct DRSIterator{I <: Integer, R <: Real, T <: AbstractArray{R}} <: ProximalAlgorithm{I,T}
x::T
f
g
Expand All @@ -23,11 +23,11 @@ end
################################################################################
# Constructor(s)

function DRSIterator(x0::BlockArray{R}; f=Zero(), g=Zero(), gamma::R=1.0, maxit::I=10000, tol::R=1e-4, verbose=1, verbose_freq = 100) where {I, R}
y = blockcopy(x0)
r = blockcopy(x0)
z = blockcopy(x0)
FPR_x = blockcopy(x0)
function DRSIterator(x0::AbstractArray{R}; f=Zero(), g=Zero(), gamma::R=1.0, maxit::I=10000, tol::R=1e-4, verbose=1, verbose_freq = 100) where {I, R}
y = copy(x0)
r = copy(x0)
z = copy(x0)
FPR_x = copy(x0)
FPR_x .= Inf
return DRSIterator{I, R, typeof(x0)}(x0, f, g, gamma, maxit, tol, verbose, verbose_freq, y, r, z, FPR_x)
end
Expand All @@ -37,7 +37,7 @@ end

maxit(sol::DRSIterator) = sol.maxit

converged(sol::DRSIterator, it) = it > 0 && blockmaxabs(sol.FPR_x)/sol.gamma <= sol.tol
converged(sol::DRSIterator, it) = it > 0 && maximum(abs,sol.FPR_x)/sol.gamma <= sol.tol

verbose(sol::DRSIterator) = sol.verbose > 0
verbose(sol::DRSIterator, it) = sol.verbose > 0 && (sol.verbose == 2 ? true : (it == 1 || it%sol.verbose_freq == 0))
Expand All @@ -48,12 +48,12 @@ function display(sol::DRSIterator)
end

function display(sol::DRSIterator, it)
@printf("%6d | %7.4e | %7.4e |\n", it, sol.gamma, blockmaxabs(sol.FPR_x)/sol.gamma)
@printf("%6d | %7.4e | %7.4e |\n", it, sol.gamma, maximum(abs,sol.FPR_x)/sol.gamma)
end

function Base.show(io::IO, sol::DRSIterator)
println(io, "Douglas-Rachford Splitting" )
println(io, "fpr : $(blockmaxabs(sol.FPR_x))")
println(io, "fpr : $(maximum(abs,sol.FPR_x))")
print( io, "gamma : $(sol.gamma)")
end

Expand Down
97 changes: 44 additions & 53 deletions src/algorithms/ForwardBackward.jl
Expand Up @@ -50,31 +50,31 @@ end
# Constructor

function FBSIterator(x0::D;
fs::FS=Zero(), As::AS=Identity(blocksize(x0)),
fq::FQ=Zero(), Aq::AQ=Identity(blocksize(x0)),
fs::FS=Zero(), As::AS=Identity(size(x0)),
fq::FQ=Zero(), Aq::AQ=Identity(size(x0)),
g::G=Zero(),
gamma::R=-1.0, maxit::I=10000, tol::R=1e-4,
adaptive::Bool=false, fast::Bool=false,
verbose::I=1, verbose_freq::I = 100) where {I, R, D, FS, AS, FQ, AQ, G}
x = blockcopy(x0)
y = blockzeros(x0)
z = blockzeros(x0)
z_prev = blockzeros(x0)
FPR_x = blockzeros(x0)
x = copy(x0)
y = zero(x0)
z = zero(x0)
z_prev = zero(x0)
FPR_x = zero(x0)
Aqx = Aq*x
Asx = As*x
Aqz = blockzeros(Aqx)
Asz = blockzeros(Asx)
gradfq_Aqx = blockzeros(Aqx)
gradfs_Asx = blockzeros(Asx)
Aqt_gradfq_Aqx = blockzeros(x0)
Ast_gradfs_Asx = blockzeros(x0)
At_gradf_Ax = blockzeros(x0)
Aqz_prev = blockzeros(Aqx)
Asz_prev = blockzeros(Asx)
gradfq_Aqz = blockzeros(Aqx)
gradfs_Asz = blockzeros(Asx)
gradfq_Aqz_prev = blockzeros(Aqx)
Aqz = zero(Aqx)
Asz = zero(Asx)
gradfq_Aqx = zero(Aqx)
gradfs_Asx = zero(Asx)
Aqt_gradfq_Aqx = zero(x0)
Ast_gradfs_Asx = zero(x0)
At_gradf_Ax = zero(x0)
Aqz_prev = zero(Aqx)
Asz_prev = zero(Asx)
gradfq_Aqz = zero(Aqx)
gradfs_Asz = zero(Asx)
gradfq_Aqz_prev = zero(Aqx)
CQ = typeof(Aqx)
CS = typeof(Asx)
FBSIterator{I, R, D, CS, FS, AS, CQ, FQ, AQ, G}(x,
Expand All @@ -96,7 +96,7 @@ end

maxit(sol::FBSIterator{I}) where {I} = sol.maxit

converged(sol::FBSIterator{I, R, D}, it::I) where {I, R, D} = it > 0 && blockmaxabs(sol.FPR_x)/sol.gamma <= sol.tol
converged(sol::FBSIterator{I, R, D}, it::I) where {I, R, D} = it > 0 && maximum(abs,sol.FPR_x)/sol.gamma <= sol.tol

verbose(sol::FBSIterator) = sol.verbose > 0
verbose(sol::FBSIterator, it) = sol.verbose > 0 && (sol.verbose == 2 ? true : (it == 1 || it%sol.verbose_freq == 0))
Expand All @@ -107,12 +107,12 @@ function display(sol::FBSIterator)
end

function display(sol::FBSIterator, it)
@printf("%6d | %7.4e | %7.4e |\n", it, sol.gamma, blockmaxabs(sol.FPR_x)/sol.gamma)
@printf("%6d | %7.4e | %7.4e |\n", it, sol.gamma, maximum(abs,sol.FPR_x)/sol.gamma)
end

function Base.show(io::IO, sol::FBSIterator)
println(io, (sol.fast ? "Fast " : "")*"Forward-Backward Splitting" )
println(io, "fpr : $(blockmaxabs(sol.FPR_x))")
println(io, "fpr : $(maximum(abs,sol.FPR_x))")
print( io, "gamma : $(sol.gamma)")
end

Expand All @@ -131,30 +131,29 @@ function initialize!(sol::FBSIterator{I, R, D, CS, FS, AS, CQ, FQ, AQ, G}) where
sol.fs_Asx = gradient!(sol.gradfs_Asx, sol.fs, sol.Asx)
mul!(sol.Ast_gradfs_Asx, sol.As', sol.gradfs_Asx)
mul!(sol.Aqt_gradfq_Aqx, sol.Aq', sol.gradfq_Aqx)
blockaxpy!(sol.At_gradf_Ax, sol.Ast_gradfs_Asx, 1.0, sol.Aqt_gradfq_Aqx)
sol.At_gradf_Ax .= sol.Ast_gradfs_Asx .+ sol.Aqt_gradfq_Aqx
sol.f_Ax = sol.fs_Asx + sol.fq_Aqx

if sol.gamma <= 0.0 # estimate L in this case, and set gamma = 1/L
# this part should be as follows:
# 1) if adaptive = false and only fq is present then L is "accurate"
# 2) otherwise L is "inaccurate" and set adaptive = true
# TODO: implement case 1), now 2) is always performed
# xeps = sol.x .+ sqrt(eps())
xeps = (x -> x .+ sqrt(eps())).(sol.x)
xeps = sol.x .+ sqrt(eps())
Aqxeps = sol.Aq*xeps
gradfq_Aqxeps, = gradient(sol.fq, Aqxeps)
Asxeps = sol.As*xeps
gradfs_Asxeps, = gradient(sol.fs, Asxeps)
At_gradf_Axeps = sol.As'*gradfs_Asxeps .+ sol.Aq'*gradfq_Aqxeps
L = blockvecnorm(sol.At_gradf_Ax .- At_gradf_Axeps)/(sqrt(eps()*blocklength(xeps)))
L = norm(sol.At_gradf_Ax .- At_gradf_Axeps)/(sqrt(eps()*length(xeps)))
sol.adaptive = true
# in both cases set gamma = 1/L
sol.gamma = 1.0/L
end

blockaxpy!(sol.y, sol.x, -sol.gamma, sol.At_gradf_Ax)
sol.y .= sol.x .- sol.gamma .* sol.At_gradf_Ax
prox!(sol.z, sol.g, sol.y, sol.gamma)
blockaxpy!(sol.FPR_x, sol.x, -1.0, sol.z)
sol.FPR_x .= sol.x .- sol.z

return sol.z
end
Expand All @@ -169,18 +168,18 @@ function iterate!(sol::FBSIterator{I, R, D, CS, FS, AS, CQ, FQ, AQ, G}, it::I) w

if sol.adaptive
for it_gam = 1:100 # TODO: replace/complement with lower bound on gamma
normFPR_x = blockvecnorm(sol.FPR_x)
uppbnd = sol.f_Ax - real(blockvecdot(sol.At_gradf_Ax, sol.FPR_x)) + 0.5/sol.gamma*normFPR_x^2
normFPR_x = norm(sol.FPR_x)
uppbnd = sol.f_Ax - real(dot(sol.At_gradf_Ax, sol.FPR_x)) + 0.5/sol.gamma*normFPR_x^2
mul!(sol.Aqz, sol.Aq, sol.z)
fq_Aqz = gradient!(sol.gradfq_Aqz, sol.fq, sol.Aqz)
mul!(sol.Asz, sol.As, sol.z)
fs_Asz = gradient!(sol.gradfs_Asz, sol.fs, sol.Asz)
f_Az = fs_Asz + fq_Aqz
if f_Az > uppbnd + 1e-6*abs(sol.f_Ax)
sol.gamma = 0.5*sol.gamma
blockaxpy!(sol.y, sol.x, -sol.gamma, sol.At_gradf_Ax)
sol.y .= sol.x - sol.gamma .* sol.At_gradf_Ax
prox!(sol.z, sol.g, sol.y, sol.gamma)
blockaxpy!(sol.FPR_x, sol.x, -1.0, sol.z)
sol.FPR_x .= sol.x .- sol.z
else
break
end
Expand All @@ -198,7 +197,7 @@ function iterate!(sol::FBSIterator{I, R, D, CS, FS, AS, CQ, FQ, AQ, G}, it::I) w
sol.gradfs_Asx, sol.gradfs_Asz = sol.gradfs_Asz, sol.gradfs_Asx
mul!(sol.Ast_gradfs_Asx, sol.As', sol.gradfs_Asx)
mul!(sol.Aqt_gradfq_Aqx, sol.Aq', sol.gradfq_Aqx)
blockaxpy!(sol.At_gradf_Ax, sol.Ast_gradfs_Asx, 1.0, sol.Aqt_gradfq_Aqx)
sol.At_gradf_Ax .= sol.Ast_gradfs_Asx .+ sol.Aqt_gradfq_Aqx
sol.f_Ax = sol.fs_Asx + sol.fq_Aqx
end
else
Expand All @@ -207,27 +206,19 @@ function iterate!(sol::FBSIterator{I, R, D, CS, FS, AS, CQ, FQ, AQ, G}, it::I) w
extr = (sol.theta - 1.0)/theta1
sol.theta = theta1
# perform extrapolation
#sol.x .= sol.z .+ extr.*(sol.z .- sol.z_prev)
blockaxpy!(sol.x, sol.z, -1, sol.z_prev)
blockaxpy!(sol.x, sol.z, extr, sol.x)
sol.x .= sol.z .+ extr.*(sol.z .- sol.z_prev)

sol.z, sol.z_prev = sol.z_prev, sol.z
if sol.adaptive == true
# extrapolate other extrapolable quantities
# diff_Aqx = (sol.Aqz .- sol.Aqz_prev)
# diff_gradfq_Aqx = (sol.gradfq_Aqz .- sol.gradfq_Aqz_prev)
blockaxpy!(sol.Aqx, sol.Aqz, -1.0, sol.Aqz_prev)
blockaxpy!(sol.gradfq_Aqx, sol.gradfq_Aqz, -1.0, sol.gradfq_Aqz_prev)
coeff_linear = real(blockvecdot(sol.gradfq_Aqz, sol.Aqx))
coeff_quadr = real(blockvecdot(sol.Aqx, sol.gradfq_Aqx))
sol.Aqx .= sol.Aqz .- sol.Aqz_prev
sol.gradfq_Aqx .= sol.gradfq_Aqz .- sol.gradfq_Aqz_prev
coeff_linear = real(dot(sol.gradfq_Aqz, sol.Aqx))
coeff_quadr = real(dot(sol.Aqx, sol.gradfq_Aqx))
sol.fq_Aqx = fq_Aqz + extr*coeff_linear + 0.5*coeff_quadr*extr^2
# sol.Aqx .= sol.Aqz .+ extr.*diff_Aqx
blockaxpy!(sol.Aqx, sol.Aqz, extr, sol.Aqx)
# sol.gradfq_Aqx .= sol.gradfq_Aqz .+ extr.*diff_gradfq_Aqx
blockaxpy!(sol.gradfq_Aqx, sol.gradfq_Aqz, extr, sol.gradfq_Aqx)
# sol.Asx .= sol.Asz .+ extr.*(sol.Asz .- sol.Asz_prev)
blockaxpy!(sol.Asx, sol.Asz, -1.0, sol.Asz_prev)
blockaxpy!(sol.Asx, sol.Asz, extr, sol.Asx )
sol.Aqx .= sol.Aqz .+ extr.*(sol.Aqz .- sol.Aqz_prev)
sol.gradfq_Aqx .= sol.gradfq_Aqz .+ extr.*(sol.gradfq_Aqz .- sol.gradfq_Aqz_prev)
sol.Asx .= sol.Asz .+ extr .*(sol.Asz .- sol.Asz_prev)
# store the z-quantities for future extrapolation
sol.Aqz_prev, sol.Aqz = sol.Aqz, sol.Aqz_prev
sol.gradfq_Aqz_prev, sol.gradfq_Aqz = sol.gradfq_Aqz, sol.gradfq_Aqz_prev
Expand All @@ -237,7 +228,7 @@ function iterate!(sol::FBSIterator{I, R, D, CS, FS, AS, CQ, FQ, AQ, G}, it::I) w
mul!(sol.Ast_gradfs_Asx, sol.As', sol.gradfs_Asx)
# TODO: we can probably save the MATVEC by Aq' in the next line
mul!(sol.Aqt_gradfq_Aqx, sol.Aq', sol.gradfq_Aqx)
blockaxpy!(sol.At_gradf_Ax, sol.Ast_gradfs_Asx, 1.0, sol.Aqt_gradfq_Aqx)
sol.At_gradf_Ax .= sol.Ast_gradfs_Asx .+ sol.Aqt_gradfq_Aqx
sol.f_Ax = sol.fs_Asx + sol.fq_Aqx
end
end
Expand All @@ -248,12 +239,12 @@ function iterate!(sol::FBSIterator{I, R, D, CS, FS, AS, CQ, FQ, AQ, G}, it::I) w
sol.fs_Asx = gradient!(sol.gradfs_Asx, sol.fs, sol.Asx)
mul!(sol.Ast_gradfs_Asx, sol.As', sol.gradfs_Asx)
mul!(sol.Aqt_gradfq_Aqx, sol.Aq', sol.gradfq_Aqx)
blockaxpy!(sol.At_gradf_Ax, sol.Ast_gradfs_Asx, 1.0, sol.Aqt_gradfq_Aqx)
sol.At_gradf_Ax .= sol.Ast_gradfs_Asx .+ sol.Aqt_gradfq_Aqx
sol.f_Ax = sol.fs_Asx + sol.fq_Aqx
end
blockaxpy!(sol.y, sol.x, -sol.gamma, sol.At_gradf_Ax)
sol.y .= sol.x .- sol.gamma .* sol.At_gradf_Ax
prox!(sol.z, sol.g, sol.y, sol.gamma)
blockaxpy!(sol.FPR_x, sol.x, -1.0, sol.z)
sol.FPR_x .= sol.x .- sol.z

return sol.z

Expand Down

0 comments on commit 1556b41

Please sign in to comment.