Skip to content

Add KnownJacobianSparsityDetector and KnownHessianSparsityDetector #81

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ ADTypes.AbstractSparsityDetector
ADTypes.jacobian_sparsity
ADTypes.hessian_sparsity
ADTypes.NoSparsityDetector
ADTypes.KnownJacobianSparsityDetector
ADTypes.KnownHessianSparsityDetector
```

### Coloring algorithm
Expand Down
61 changes: 61 additions & 0 deletions src/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,67 @@ jacobian_sparsity(f, x, ::NoSparsityDetector) = trues(length(f(x)), length(x))
jacobian_sparsity(f!, y, x, ::NoSparsityDetector) = trues(length(y), length(x))
hessian_sparsity(f, x, ::NoSparsityDetector) = trues(length(x), length(x))

"""
KnownJacobianSparsityDetector(jacobian_sparsity::AbstractMatrix) <: AbstractSparsityDetector

Trivial sparsity detector used to return a known Jacobian sparsity pattern.

# See also

- [`AbstractSparsityDetector`](@ref)
- [`KnownHessianSparsityDetector`](@ref)
"""
struct KnownJacobianSparsityDetector{J <: AbstractMatrix} <: AbstractSparsityDetector
jacobian_sparsity::J
end

function jacobian_sparsity(f, x, sd::KnownJacobianSparsityDetector)
sz = size(sd.jacobian_sparsity)
sz_expected = (length(f(x)), length(x))
sz != sz_expected &&
throw(DimensionMismatch("Jacobian size $sz of KnownJacobianSparsityDetector doesn't match expected size $sz_expected."))
return sd.jacobian_sparsity
end
function jacobian_sparsity(f!, y, x, sd::KnownJacobianSparsityDetector)
sz = size(sd.jacobian_sparsity)
sz_expected = (length(y), length(x))
sz != sz_expected &&
throw(DimensionMismatch("Jacobian size $sz of KnownJacobianSparsityDetector doesn't match expected size $sz_expected."))
return sd.jacobian_sparsity
end
function hessian_sparsity(f, x, sd::KnownJacobianSparsityDetector)
error("KnownJacobianSparsityDetector can't be used to compute Hessian sparsity.")
end

"""
KnownHessianSparsityDetector(hessian_sparsity::AbstractMatrix) <: AbstractSparsityDetector

Trivial sparsity detector used to return a known Hessian sparsity pattern.

# See also

- [`AbstractSparsityDetector`](@ref)
- [`KnownJacobianSparsityDetector`](@ref)
"""
struct KnownHessianSparsityDetector{H <: AbstractMatrix} <: AbstractSparsityDetector
hessian_sparsity::H
end

function hessian_sparsity(f, x, sd::KnownHessianSparsityDetector)
sz = size(sd.hessian_sparsity)
sz_expected = (length(x), length(x))
sz != sz_expected &&
throw(DimensionMismatch("Hessian size $sz of KnownHessianSparsityDetector doesn't match expected size $sz_expected."))
return sd.hessian_sparsity
end

function jacobian_sparsity(f, x, sd::KnownHessianSparsityDetector)
error("KnownHessianSparsityDetector can't be used to compute Jacobian sparsity.")
end
function jacobian_sparsity(f!, y, x, sd::KnownHessianSparsityDetector)
error("KnownHessianSparsityDetector can't be used to compute Jacobian sparsity.")
end

## Coloring algorithm

"""
Expand Down
2 changes: 2 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ using ADTypes: AbstractADType,
SymbolicMode
using ADTypes: dense_ad,
NoSparsityDetector,
KnownJacobianSparsityDetector,
KnownHessianSparsityDetector,
sparsity_detector,
jacobian_sparsity,
hessian_sparsity,
Expand Down
122 changes: 104 additions & 18 deletions test/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,119 @@
end

@testset "Sparsity detector" begin
sd = NoSparsityDetector()

f_jac1(x) = vcat(x, x)
f_jac2(x) = hcat(x, x)
function f_jac! end
f_hess(x) = sum(x)

for x in (rand(2), rand(2, 3)), f in (f_jac1, f_jac2)
y = f(x)
Js = jacobian_sparsity(f, x, sd)
@test Js isa AbstractMatrix
@test size(Js) == (length(y), length(x))
@test all(isone, Js)
@testset "NoSparsityDetector" begin
sd = NoSparsityDetector()

for x in (rand(2), rand(2, 3)), f in (f_jac1, f_jac2)
y = f(x)
Js = jacobian_sparsity(f, x, sd)
@test Js isa AbstractMatrix
@test size(Js) == (length(y), length(x))
@test all(isone, Js)
end

for x in (rand(2), rand(2, 3)), y in (rand(5), rand(5, 6))
Js = jacobian_sparsity(f_jac!, y, x, sd)
@test Js isa AbstractMatrix
@test size(Js) == (length(y), length(x))
@test all(isone, Js)
end

for x in (rand(2), rand(2, 3))
Hs = hessian_sparsity(f_hess, x, sd)
@test Hs isa AbstractMatrix
@test size(Hs) == (length(x), length(x))
@test all(isone, Hs)
end
end

for x in (rand(2), rand(2, 3)), y in (rand(5), rand(5, 6))
Js = jacobian_sparsity(f_jac!, y, x, sd)
@test Js isa AbstractMatrix
@test size(Js) == (length(y), length(x))
@test all(isone, Js)
@testset "KnownJacobianSparsityDetector" begin
@testset "Out-of-place functions" begin
for sx in ((2,), (2, 3)), f in (f_jac1, f_jac2)
x = rand(sx...)
nx = length(x)
Jref = rand(Bool, 2 * nx, nx)
sd = KnownJacobianSparsityDetector(Jref)
Js = jacobian_sparsity(f, x, sd)
@test Js isa AbstractMatrix
@test size(Js) == (2 * nx, nx)
@test Js === Jref
end
end
@testset "In-place functions" begin
for sx in ((2,), (2, 3)), sy in ((5,), (5, 6))
x, y = rand(sx...), rand(sy...)
nx, ny = length(x), length(y)
Jref = rand(Bool, ny, nx)
sd = KnownJacobianSparsityDetector(Jref)
Js = jacobian_sparsity(f_jac!, y, x, sd)
@test Js isa AbstractMatrix
@test size(Js) == (ny, nx)
@test Js === Jref
end
end
@testset "Exceptions: hessian_sparsity not supported" begin
for sx in ((2,), (2, 3))
x = rand(sx...)
nx = length(x)
Href = rand(Bool, nx, nx)
sd = KnownJacobianSparsityDetector(Href)
@test_throws ErrorException hessian_sparsity(f_hess, x, sd)
end
end
@testset "Exceptions: DimensionMismatch" begin
sd = KnownJacobianSparsityDetector(rand(Bool, 6, 7)) # wrong Jacobian size
for x in (rand(2), rand(2, 3)), f in (f_jac1, f_jac2)
@test_throws DimensionMismatch jacobian_sparsity(f, x, sd)
end
for x in (rand(2), rand(2, 3)), y in (rand(5), rand(5, 6))
@test_throws DimensionMismatch jacobian_sparsity(f_jac!, y, x, sd)
end
end
end
@testset "KnownHessianSparsityDetector" begin
for sx in ((2,), (2, 3))
x = rand(sx...)
nx = length(x)
Href = rand(Bool, nx, nx)
sd = KnownHessianSparsityDetector(Href)

for x in (rand(2), rand(2, 3))
Hs = hessian_sparsity(f_hess, x, sd)
@test Hs isa AbstractMatrix
@test size(Hs) == (length(x), length(x))
@test all(isone, Hs)
Hs = hessian_sparsity(f_hess, x, sd)
@test Hs isa AbstractMatrix
@test size(Hs) == (nx, nx)
@test Hs === Href
end
@testset "Exceptions: jacobian_sparsity not supported" begin
@testset "Out-of-place functions" begin
for sx in ((2,), (2, 3)), f in (f_jac1, f_jac2)
x = rand(sx...)
nx = length(x)
Jref = rand(Bool, 2 * nx, nx)
sd = KnownHessianSparsityDetector(Jref)
@test_throws ErrorException jacobian_sparsity(f, x, sd)
end
end
@testset "In-place functions" begin
for sx in ((2,), (2, 3)), sy in ((5,), (5, 6))
x, y = rand(sx...), rand(sy...)
nx, ny = length(x), length(y)
Jref = rand(Bool, ny, nx)
sd = KnownHessianSparsityDetector(Jref)
@test_throws ErrorException jacobian_sparsity(f_jac!, y, x, sd)
end
end
end
@testset "Exceptions: DimensionMismatch" begin
sd = KnownHessianSparsityDetector(rand(Bool, 2, 3)) #wrong Hessian size
for x in (rand(2), rand(2, 3))
@test_throws DimensionMismatch hessian_sparsity(f_hess, x, sd)
end
end
end
end

Expand Down
Loading