Skip to content

Commit f206682

Browse files
authored
Add KnownJacobianSparsityDetector and KnownHessianSparsityDetector (#81)
* Add `KnownSparsityDetector` * Split Jacobians and Hessians * Add tests * More tests * Update docs * Throw `ArgumentError` * Add more testsets
1 parent c27ebd3 commit f206682

File tree

4 files changed

+174
-18
lines changed

4 files changed

+174
-18
lines changed

docs/src/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ ADTypes.AbstractSparsityDetector
6969
ADTypes.jacobian_sparsity
7070
ADTypes.hessian_sparsity
7171
ADTypes.NoSparsityDetector
72+
ADTypes.KnownJacobianSparsityDetector
73+
ADTypes.KnownHessianSparsityDetector
7274
```
7375

7476
### Coloring algorithm

src/sparse.jl

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,67 @@ jacobian_sparsity(f, x, ::NoSparsityDetector) = trues(length(f(x)), length(x))
4242
jacobian_sparsity(f!, y, x, ::NoSparsityDetector) = trues(length(y), length(x))
4343
hessian_sparsity(f, x, ::NoSparsityDetector) = trues(length(x), length(x))
4444

45+
"""
46+
KnownJacobianSparsityDetector(jacobian_sparsity::AbstractMatrix) <: AbstractSparsityDetector
47+
48+
Trivial sparsity detector used to return a known Jacobian sparsity pattern.
49+
50+
# See also
51+
52+
- [`AbstractSparsityDetector`](@ref)
53+
- [`KnownHessianSparsityDetector`](@ref)
54+
"""
55+
struct KnownJacobianSparsityDetector{J <: AbstractMatrix} <: AbstractSparsityDetector
56+
jacobian_sparsity::J
57+
end
58+
59+
function jacobian_sparsity(f, x, sd::KnownJacobianSparsityDetector)
60+
sz = size(sd.jacobian_sparsity)
61+
sz_expected = (length(f(x)), length(x))
62+
sz != sz_expected &&
63+
throw(DimensionMismatch("Jacobian size $sz of KnownJacobianSparsityDetector doesn't match expected size $sz_expected."))
64+
return sd.jacobian_sparsity
65+
end
66+
function jacobian_sparsity(f!, y, x, sd::KnownJacobianSparsityDetector)
67+
sz = size(sd.jacobian_sparsity)
68+
sz_expected = (length(y), length(x))
69+
sz != sz_expected &&
70+
throw(DimensionMismatch("Jacobian size $sz of KnownJacobianSparsityDetector doesn't match expected size $sz_expected."))
71+
return sd.jacobian_sparsity
72+
end
73+
function hessian_sparsity(f, x, sd::KnownJacobianSparsityDetector)
74+
throw(ArgumentError("KnownJacobianSparsityDetector can't be used to compute Hessian sparsity."))
75+
end
76+
77+
"""
78+
KnownHessianSparsityDetector(hessian_sparsity::AbstractMatrix) <: AbstractSparsityDetector
79+
80+
Trivial sparsity detector used to return a known Hessian sparsity pattern.
81+
82+
# See also
83+
84+
- [`AbstractSparsityDetector`](@ref)
85+
- [`KnownJacobianSparsityDetector`](@ref)
86+
"""
87+
struct KnownHessianSparsityDetector{H <: AbstractMatrix} <: AbstractSparsityDetector
88+
hessian_sparsity::H
89+
end
90+
91+
function hessian_sparsity(f, x, sd::KnownHessianSparsityDetector)
92+
sz = size(sd.hessian_sparsity)
93+
sz_expected = (length(x), length(x))
94+
sz != sz_expected &&
95+
throw(DimensionMismatch("Hessian size $sz of KnownHessianSparsityDetector doesn't match expected size $sz_expected."))
96+
return sd.hessian_sparsity
97+
end
98+
99+
function jacobian_sparsity(f, x, sd::KnownHessianSparsityDetector)
100+
throw(ArgumentError("KnownHessianSparsityDetector can't be used to compute Jacobian sparsity."))
101+
end
102+
function jacobian_sparsity(f!, y, x, sd::KnownHessianSparsityDetector)
103+
throw(ArgumentError("KnownHessianSparsityDetector can't be used to compute Jacobian sparsity."))
104+
end
105+
45106
## Coloring algorithm
46107

47108
"""

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ using ADTypes: AbstractADType,
77
SymbolicMode
88
using ADTypes: dense_ad,
99
NoSparsityDetector,
10+
KnownJacobianSparsityDetector,
11+
KnownHessianSparsityDetector,
1012
sparsity_detector,
1113
jacobian_sparsity,
1214
hessian_sparsity,

test/sparse.jl

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,124 @@
1818
end
1919

2020
@testset "Sparsity detector" begin
21-
sd = NoSparsityDetector()
22-
2321
f_jac1(x) = vcat(x, x)
2422
f_jac2(x) = hcat(x, x)
2523
function f_jac! end
2624
f_hess(x) = sum(x)
2725

28-
for x in (rand(2), rand(2, 3)), f in (f_jac1, f_jac2)
29-
y = f(x)
30-
Js = jacobian_sparsity(f, x, sd)
31-
@test Js isa AbstractMatrix
32-
@test size(Js) == (length(y), length(x))
33-
@test all(isone, Js)
26+
@testset "NoSparsityDetector" begin
27+
sd = NoSparsityDetector()
28+
29+
for x in (rand(2), rand(2, 3)), f in (f_jac1, f_jac2)
30+
y = f(x)
31+
Js = jacobian_sparsity(f, x, sd)
32+
@test Js isa AbstractMatrix
33+
@test size(Js) == (length(y), length(x))
34+
@test all(isone, Js)
35+
end
36+
37+
for x in (rand(2), rand(2, 3)), y in (rand(5), rand(5, 6))
38+
Js = jacobian_sparsity(f_jac!, y, x, sd)
39+
@test Js isa AbstractMatrix
40+
@test size(Js) == (length(y), length(x))
41+
@test all(isone, Js)
42+
end
43+
44+
for x in (rand(2), rand(2, 3))
45+
Hs = hessian_sparsity(f_hess, x, sd)
46+
@test Hs isa AbstractMatrix
47+
@test size(Hs) == (length(x), length(x))
48+
@test all(isone, Hs)
49+
end
3450
end
3551

36-
for x in (rand(2), rand(2, 3)), y in (rand(5), rand(5, 6))
37-
Js = jacobian_sparsity(f_jac!, y, x, sd)
38-
@test Js isa AbstractMatrix
39-
@test size(Js) == (length(y), length(x))
40-
@test all(isone, Js)
52+
@testset "KnownJacobianSparsityDetector" begin
53+
@testset "Jacobian sparsity detection" begin
54+
@testset "Out-of-place functions" begin
55+
for sx in ((2,), (2, 3)), f in (f_jac1, f_jac2)
56+
x = rand(sx...)
57+
nx = length(x)
58+
Jref = rand(Bool, 2 * nx, nx)
59+
sd = KnownJacobianSparsityDetector(Jref)
60+
Js = jacobian_sparsity(f, x, sd)
61+
@test Js isa AbstractMatrix
62+
@test size(Js) == (2 * nx, nx)
63+
@test Js === Jref
64+
end
65+
end
66+
@testset "In-place functions" begin
67+
for sx in ((2,), (2, 3)), sy in ((5,), (5, 6))
68+
x, y = rand(sx...), rand(sy...)
69+
nx, ny = length(x), length(y)
70+
Jref = rand(Bool, ny, nx)
71+
sd = KnownJacobianSparsityDetector(Jref)
72+
Js = jacobian_sparsity(f_jac!, y, x, sd)
73+
@test Js isa AbstractMatrix
74+
@test size(Js) == (ny, nx)
75+
@test Js === Jref
76+
end
77+
end
78+
end
79+
@testset "Exceptions: Hessian sparsity detection not supported" begin
80+
for sx in ((2,), (2, 3))
81+
x = rand(sx...)
82+
nx = length(x)
83+
Href = rand(Bool, nx, nx)
84+
sd = KnownJacobianSparsityDetector(Href)
85+
@test_throws ArgumentError hessian_sparsity(f_hess, x, sd)
86+
end
87+
end
88+
@testset "Exceptions: DimensionMismatch" begin
89+
sd = KnownJacobianSparsityDetector(rand(Bool, 6, 7)) # wrong Jacobian size
90+
for x in (rand(2), rand(2, 3)), f in (f_jac1, f_jac2)
91+
@test_throws DimensionMismatch jacobian_sparsity(f, x, sd)
92+
end
93+
for x in (rand(2), rand(2, 3)), y in (rand(5), rand(5, 6))
94+
@test_throws DimensionMismatch jacobian_sparsity(f_jac!, y, x, sd)
95+
end
96+
end
4197
end
4298

43-
for x in (rand(2), rand(2, 3))
44-
Hs = hessian_sparsity(f_hess, x, sd)
45-
@test Hs isa AbstractMatrix
46-
@test size(Hs) == (length(x), length(x))
47-
@test all(isone, Hs)
99+
@testset "KnownHessianSparsityDetector" begin
100+
@testset "Hessian sparsity detection" begin
101+
for sx in ((2,), (2, 3))
102+
x = rand(sx...)
103+
nx = length(x)
104+
Href = rand(Bool, nx, nx)
105+
sd = KnownHessianSparsityDetector(Href)
106+
107+
Hs = hessian_sparsity(f_hess, x, sd)
108+
@test Hs isa AbstractMatrix
109+
@test size(Hs) == (nx, nx)
110+
@test Hs === Href
111+
end
112+
end
113+
@testset "Exceptions: Jacobian sparsity detection not supported" begin
114+
@testset "Out-of-place functions" begin
115+
for sx in ((2,), (2, 3)), f in (f_jac1, f_jac2)
116+
x = rand(sx...)
117+
nx = length(x)
118+
Jref = rand(Bool, 2 * nx, nx)
119+
sd = KnownHessianSparsityDetector(Jref)
120+
@test_throws ArgumentError jacobian_sparsity(f, x, sd)
121+
end
122+
end
123+
@testset "In-place functions" begin
124+
for sx in ((2,), (2, 3)), sy in ((5,), (5, 6))
125+
x, y = rand(sx...), rand(sy...)
126+
nx, ny = length(x), length(y)
127+
Jref = rand(Bool, ny, nx)
128+
sd = KnownHessianSparsityDetector(Jref)
129+
@test_throws ArgumentError jacobian_sparsity(f_jac!, y, x, sd)
130+
end
131+
end
132+
end
133+
@testset "Exceptions: DimensionMismatch" begin
134+
sd = KnownHessianSparsityDetector(rand(Bool, 2, 3)) #wrong Hessian size
135+
for x in (rand(2), rand(2, 3))
136+
@test_throws DimensionMismatch hessian_sparsity(f_hess, x, sd)
137+
end
138+
end
48139
end
49140
end
50141

0 commit comments

Comments
 (0)