Skip to content

Commit 2997ed3

Browse files
committed
fixed type instability in new LBFGS, re-enabled constructors
1 parent 7c1a1cb commit 2997ed3

File tree

7 files changed

+104
-51
lines changed

7 files changed

+104
-51
lines changed

src/AbstractOperators.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export LinearOperator,
1616
# Block stuff
1717

1818
include("utilities/block.jl")
19-
include("utilities/deep.jl") # TODO: remove this eventually
19+
#include("utilities/deep.jl") # TODO: remove this eventually
2020

2121
# Predicates and properties
2222

src/linearoperators/LBFGS.jl

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ julia> d = L*grad; # compute new direction
1818
```
1919
"""
2020

21-
mutable struct LBFGS{R, T <: BlockArray, M} <: LinearOperator
22-
currmem::Integer
23-
curridx::Integer
21+
mutable struct LBFGS{R, T <: BlockArray, M, I <: Integer} <: LinearOperator
22+
currmem::I
23+
curridx::I
2424
s::T
2525
y::T
2626
s_M::Array{T, 1}
@@ -30,14 +30,32 @@ mutable struct LBFGS{R, T <: BlockArray, M} <: LinearOperator
3030
H::R
3131
end
3232

33-
function LBFGS(x::T, M::Integer) where {R, T <: BlockArray{R}}
33+
function LBFGS(x::T, M::I) where {T <: BlockArray, I <: Integer}
3434
s_M = [blockzeros(x) for i = 1:M]
3535
y_M = [blockzeros(x) for i = 1:M]
3636
s = blockzeros(x)
3737
y = blockzeros(x)
3838
ys_M = zeros(M)
3939
alphas = zeros(M)
40-
LBFGS{R, T, M}(0, 0, s, y, s_M, y_M, ys_M, alphas, one(R))
40+
R = real(eltype(x[1]))
41+
LBFGS{R, T, M, I}(0, 0, s, y, s_M, y_M, ys_M, alphas, one(R))
42+
end
43+
44+
function LBFGS(domainType::D, dim::T, M::I) where {D <: Type ,
45+
T <: Tuple, I <: Integer}
46+
x = blockzeros(domainType, dim)
47+
return LBFGS(x,M)
48+
end
49+
50+
function LBFGS(domainType::D, dim::T, M::I) where {N, D <: NTuple{N,Type},
51+
T <: NTuple{N,Tuple}, I <: Integer}
52+
x = blockzeros(domainType, dim)
53+
return LBFGS(x,M)
54+
end
55+
56+
function LBFGS(dim::T, M::I) where {T <: Tuple, I <: Integer}
57+
x = blockzeros(dim)
58+
return LBFGS(x,M)
4159
end
4260

4361
"""
@@ -46,7 +64,7 @@ end
4664
See the documentation for `LBFGS`.
4765
"""
4866

49-
function update!(L::LBFGS{R, T, M}, x::T, x_prev::T, gradx::T, gradx_prev::T) where {R, T, M}
67+
function update!(L::LBFGS{R, T, M, I}, x::T, x_prev::T, gradx::T, gradx_prev::T) where {R, T, M, I}
5068
L.s .= x .- x_prev
5169
L.y .= gradx .- gradx_prev
5270
ys = real(blockvecdot(L.s, L.y))
@@ -58,49 +76,49 @@ function update!(L::LBFGS{R, T, M}, x::T, x_prev::T, gradx::T, gradx_prev::T) wh
5876
L.ys_M[L.curridx] = ys
5977
blockcopy!(L.s_M[L.curridx], L.s)
6078
blockcopy!(L.y_M[L.curridx], L.y)
61-
yty = real(vecdot(L.y, L.y))
79+
yty = real(blockvecdot(L.y, L.y))
6280
L.H = ys/yty
6381
end
6482
return L
6583
end
6684

6785
# LBFGS operators are symmetric
6886

69-
Ac_mul_B!(x::T, L::LBFGS{R, T, M}, y::T) where {R, T, M} = A_mul_B!(x, L, y)
87+
Ac_mul_B!(x::T, L::LBFGS{R, T, M, I}, y::T) where {R, T, M, I} = A_mul_B!(x, L, y)
7088

7189
# Two-loop recursion
7290

73-
function A_mul_B!(d::T, L::LBFGS{R, T, M}, gradx::T) where {R, T, M}
91+
function A_mul_B!(d::T, L::LBFGS{R, T, M, I}, gradx::T) where {R, T, M, I}
7492
d .= gradx
7593
idx = loop1!(d,L)
7694
d .= (*).(L.H, d)
7795
d = loop2!(d,idx,L)
7896
end
7997

80-
function loop1!(d::T, L::LBFGS{R, T, M}) where {R, T, M}
98+
function loop1!(d::T, L::LBFGS{R, T, M, I}) where {R, T, M, I}
8199
idx = L.curridx
82100
for i = 1:L.currmem
83-
L.alphas[idx] = real(vecdot(L.s_M[idx], d))/L.ys_M[idx]
101+
L.alphas[idx] = real(blockvecdot(L.s_M[idx], d))/L.ys_M[idx]
84102
d .-= L.alphas[idx] .* L.y_M[idx]
85103
idx -= 1
86104
if idx == 0 idx = M end
87105
end
88106
return idx
89107
end
90108

91-
function loop2!(d::T, idx::Int, L::LBFGS{R, T, M}) where {R, T, M}
109+
function loop2!(d::T, idx::Int, L::LBFGS{R, T, M, I}) where {R, T, M, I}
92110
for i = 1:L.currmem
93111
idx += 1
94112
if idx > M idx = 1 end
95-
beta = real(vecdot(L.y_M[idx], d))/L.ys_M[idx]
113+
beta = real(blockvecdot(L.y_M[idx], d))/L.ys_M[idx]
96114
d .+= (L.alphas[idx] - beta) .* L.s_M[idx]
97115
end
98116
return d
99117
end
100118

101119
# Properties
102-
domainType(L::LBFGS{R, T, M}) where {R, T, M} = T
103-
codomainType(L::LBFGS{R, T, M}) where {R, T, M} = T
120+
domainType(L::LBFGS{R, T, M}) where {R, T, M} = blockeltype(L.y_M[1])
121+
codomainType(L::LBFGS{R, T, M}) where {R, T, M} = blockeltype(L.y_M[1])
104122

105123
size(A::LBFGS) = (blocksize(A.s), blocksize(A.s))
106124

src/utilities/block.jl

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,32 @@
1-
export RealOrComplex, BlockArray
2-
export blocksize,
3-
blocklength,
4-
blockvecnorm,
5-
blockmaxabs,
6-
blocksimilar,
7-
blockcopy,
8-
blockcopy!,
9-
blockset!,
10-
blockvecdot,
11-
blockzeros,
12-
blockaxpy!
1+
# not sure about exporting this!
2+
#export RealOrComplex, BlockArray
3+
#export blocksize,
4+
# blockeltype,
5+
# blocklength,
6+
# blockvecnorm,
7+
# blockmaxabs,
8+
# blocksimilar,
9+
# blockcopy,
10+
# blockcopy!,
11+
# blockset!,
12+
# blockvecdot,
13+
# blockzeros,
14+
# blockaxpy!
1315

1416
# Define block-arrays
1517

1618
const RealOrComplex{R} = Union{R, Complex{R}}
17-
const BlockArray{R} = Union{AbstractArray{C, N} where {C <: RealOrComplex{R}, N}, Tuple{Vararg{AbstractArray{C, N} where {C <: RealOrComplex{R}, N}}}}
19+
const BlockArray{R} = Union{AbstractArray{C, N} where {C <: RealOrComplex{R}, N},
20+
Tuple{Vararg{AbstractArray{C, N} where {C <: RealOrComplex{R}, N}}}}
1821

1922
# Operations on block-arrays
2023

2124
blocksize(x::Tuple) = blocksize.(x)
2225
blocksize(x::AbstractArray) = size(x)
2326

27+
blockeltype(x::Tuple) = blockeltype.(x)
28+
blockeltype(x::AbstractArray) = eltype(x)
29+
2430
blocklength(x::Tuple) = sum(blocklength.(x))
2531
blocklength(x::AbstractArray) = length(x)
2632

test/runtests.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ verb = true
99

1010
@testset "AbstractOperators" begin
1111

12-
@testset "Tuple operations" begin
13-
include("test_deep.jl")
14-
end
12+
#@testset "Tuple operations" begin
13+
# include("test_deep.jl")
14+
#end
1515

1616
@testset "Linear operators" begin
1717
include("test_linear_operators.jl")
@@ -26,12 +26,12 @@ end
2626
include("test_nonlinear_operators_calculus.jl")
2727
end
2828

29-
@testset "Syntax shorthands" begin
30-
include("test_syntax.jl")
31-
end
32-
3329
@testset "L-BFGS" begin
3430
include("test_lbfgs.jl")
3531
end
3632

33+
@testset "Syntax shorthands" begin
34+
include("test_syntax.jl")
35+
end
36+
3737
end

test/test_lbfgs.jl

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# @printf("\nTesting L-BFGS routines\n")
1+
@printf("\nTesting L-BFGS routines\n")
2+
3+
function test_lbfgs()
24

35
Q = [32.0000 13.1000 -4.9000 -3.0000 6.0000 2.2000 2.6000 3.4000 -1.9000 -7.5000;
46
13.1000 18.3000 -5.3000 -9.5000 3.0000 2.1000 3.9000 3.0000 -3.6000 -4.4000;
@@ -60,14 +62,41 @@ for i = 1:5
6062

6163
dir_ref = dirs_ref[:,i]
6264

63-
@time A_mul_B!(dir, H, -grad)
65+
gradm = -grad
66+
@time A_mul_B!(dir, H, gradm)
6467
@test vecnorm(dir-dir_ref, Inf)/(1+vecnorm(dir_ref, Inf)) <= 1e-15
6568

66-
@time A_mul_B!(dirdir, HH, (-grad, -grad))
69+
gradm2 = (-grad,-grad)
70+
@time A_mul_B!(dirdir, HH, gradm2)
6771
@test vecnorm(dirdir[1]-dir_ref, Inf)/(1+vecnorm(dir_ref, Inf)) <= 1e-15
6872
@test vecnorm(dirdir[2]-dir_ref, Inf)/(1+vecnorm(dir_ref, Inf)) <= 1e-15
6973

7074
x_old = x;
7175
grad_old = grad;
7276

7377
end
78+
79+
end
80+
81+
test_lbfgs()
82+
83+
#test other constructors
84+
mem = 3
85+
x = (zeros(10),zeros(Complex{Float64},10))
86+
H = LBFGS(x, mem)
87+
println(H)
88+
89+
dim = (10,)
90+
H = LBFGS(dim, mem)
91+
println(H)
92+
93+
dim = ((10,),(10,))
94+
H = LBFGS(dim, mem)
95+
println(H)
96+
97+
D = (Float64,Complex{Float64})
98+
dim = ((10,),(10,))
99+
H = LBFGS(D,dim, mem)
100+
println(H)
101+
102+

test/test_linear_operators_calculus.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ y = test_op(op, x, y0, verb)
650650
p = randperm(ndoms(op,2))
651651
y2 = op[p]*x[p]
652652

653-
@test AbstractOperators.deepvecnorm(y .- y2) <= 1e-8
653+
@test AbstractOperators.blockvecnorm(y .- y2) <= 1e-8
654654

655655
# test Scale of Sum
656656

test/utils.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@ function test_op(A::AbstractOperator, x, y, verb::Bool = false)
44
verb && (println(); show(A); println())
55

66
Ax = A*x
7-
Ax2 = AbstractOperators.deepsimilar(Ax)
7+
Ax2 = AbstractOperators.blocksimilar(Ax)
88
verb && println("forward preallocated")
99
A_mul_B!(Ax2, A, x) #verify in-place linear operator works
1010
verb && @time A_mul_B!(Ax2, A, x)
1111

12-
@test AbstractOperators.deepvecnorm(Ax .- Ax2) <= 1e-8
12+
@test AbstractOperators.blockvecnorm(Ax .- Ax2) <= 1e-8
1313

1414
Acy = A'*y
15-
Acy2 = AbstractOperators.deepsimilar(Acy)
15+
Acy2 = AbstractOperators.blocksimilar(Acy)
1616
verb && println("adjoint preallocated")
1717
Ac_mul_B!(Acy2, A, y) #verify in-place linear operator works
1818
verb && @time Ac_mul_B!(Acy2, A, y)
1919

20-
@test AbstractOperators.deepvecnorm(Acy .- Acy2) <= 1e-8
20+
@test AbstractOperators.blockvecnorm(Acy .- Acy2) <= 1e-8
2121

22-
s1 = real(AbstractOperators.deepvecdot(Ax2, y))
23-
s2 = real(AbstractOperators.deepvecdot(x, Acy2))
22+
s1 = real(AbstractOperators.blockvecdot(Ax2, y))
23+
s2 = real(AbstractOperators.blockvecdot(x, Acy2))
2424
@test abs( s1 - s2 ) < 1e-8
2525

2626
return Ax
@@ -32,31 +32,31 @@ function test_NLop(A::AbstractOperator, x, y, verb::Bool = false)
3232
verb && (println(),println(A))
3333

3434
Ax = A*x
35-
Ax2 = AbstractOperators.deepsimilar(Ax)
35+
Ax2 = AbstractOperators.blocksimilar(Ax)
3636
verb && println("forward preallocated")
3737
A_mul_B!(Ax2, A, x) #verify in-place linear operator works
3838
verb && @time A_mul_B!(Ax2, A, x)
3939

4040
@test_throws ErrorException A'
4141

42-
@test AbstractOperators.deepvecnorm(Ax .- Ax2) <= 1e-8
42+
@test AbstractOperators.blockvecnorm(Ax .- Ax2) <= 1e-8
4343

4444
J = Jacobian(A,x)
4545
verb && println(J)
4646

4747
grad = J'*y
4848
A_mul_B!(Ax2, A, x) #redo forward
4949
verb && println("jacobian Ac_mul_B! preallocated")
50-
grad2 = AbstractOperators.deepsimilar(grad)
50+
grad2 = AbstractOperators.blocksimilar(grad)
5151
Ac_mul_B!(grad2, J, y) #verify in-place linear operator works
5252
verb && A_mul_B!(Ax2, A, x) #redo forward
5353
verb && @time Ac_mul_B!(grad2, J, y)
5454

55-
@test AbstractOperators.deepvecnorm(grad .- grad2) < 1e-8
55+
@test AbstractOperators.blockvecnorm(grad .- grad2) < 1e-8
5656

5757
grad3 = gradient_fd(A,Ax,x,y) #calculate gradient using finite differences
5858

59-
@test AbstractOperators.deepvecnorm(grad .- grad3) < 1e-4
59+
@test AbstractOperators.blockvecnorm(grad .- grad3) < 1e-4
6060

6161
return Ax, grad
6262
end

0 commit comments

Comments
 (0)