Skip to content
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

Optimize sparse AD #269

Merged
merged 2 commits into from
Jul 11, 2024
Merged
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
42 changes: 29 additions & 13 deletions src/sparse_hessian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ struct SparseADHessian{Tag, GT, S, T} <: ADNLPModels.ADBackend
colptr::Vector{Int}
colors::Vector{Int}
ncolors::Int
dcolors::Dict{Int, Vector{UnitRange{Int}}}
res::S
lz::Vector{ForwardDiff.Dual{Tag, T, 1}}
glz::Vector{ForwardDiff.Dual{Tag, T, 1}}
Expand Down Expand Up @@ -37,6 +38,13 @@ function SparseADHessian(
rowval = trilH.rowval
colptr = trilH.colptr

# The indices of the nonzero elements in `vals` that will be processed by color `c` are stored in `dcolors[c]`.
dcolors = Dict(i => UnitRange{Int}[] for i=1:ncolors)
for (i, color) in enumerate(colors)
range_vals = colptr[i]:(colptr[i + 1] - 1)
push!(dcolors[color], range_vals)
end

# prepare directional derivatives
res = similar(x0)

Expand Down Expand Up @@ -65,7 +73,7 @@ function SparseADHessian(
Hvp = fill!(S(undef, ntotal), 0)
y = fill!(S(undef, ncon), 0)

return SparseADHessian(d, rowval, colptr, colors, ncolors, res, lz, glz, sol, longv, Hvp, ∇φ!, y)
return SparseADHessian(d, rowval, colptr, colors, ncolors, dcolors, res, lz, glz, sol, longv, Hvp, ∇φ!, y)
end

struct SparseReverseADHessian{T, S, Tagf, F, Tagψ, P} <: ADNLPModels.ADBackend
Expand All @@ -74,6 +82,7 @@ struct SparseReverseADHessian{T, S, Tagf, F, Tagψ, P} <: ADNLPModels.ADBackend
colptr::Vector{Int}
colors::Vector{Int}
ncolors::Int
dcolors::Dict{Int, Vector{UnitRange{Int}}}
res::S
z::Vector{ForwardDiff.Dual{Tagf, T, 1}}
gz::Vector{ForwardDiff.Dual{Tagf, T, 1}}
Expand Down Expand Up @@ -109,6 +118,13 @@ function SparseReverseADHessian(
rowval = trilH.rowval
colptr = trilH.colptr

# The indices of the nonzero elements in `vals` that will be processed by color `c` are stored in `dcolors[c]`.
dcolors = Dict(i => UnitRange{Int}[] for i=1:ncolors)
for (i, color) in enumerate(colors)
range_vals = colptr[i]:(colptr[i + 1] - 1)
push!(dcolors[color], range_vals)
end

# prepare directional derivatives
res = similar(x0)

Expand Down Expand Up @@ -147,6 +163,7 @@ function SparseReverseADHessian(
colptr,
colors,
ncolors,
dcolors,
res,
z,
gz,
Expand Down Expand Up @@ -213,12 +230,12 @@ function sparse_hess_coord!(
b.∇φ!(b.glz, b.lz)
ForwardDiff.extract_derivative!(Tag, b.Hvp, b.glz)
b.res .= view(b.Hvp, (ncon + 1):(ncon + nvar))
for j = 1:nvar
if b.colors[j] == icol
for k = b.colptr[j]:(b.colptr[j + 1] - 1)
i = b.rowval[k]
vals[k] = b.res[i]
end

# Store in `vals` the nonzeros of each column of the Hessian computed with color `icol`
for range_vals in b.dcolors[icol]
for k in range_vals
row = b.rowval[k]
vals[k] = b.res[row]
end
end
end
Expand Down Expand Up @@ -251,12 +268,11 @@ function sparse_hess_coord!(
ForwardDiff.extract_derivative!(Tagψ, b.Hv_temp, b.gzψ)
b.res .+= b.Hv_temp

for j = 1:nvar
if b.colors[j] == icol
for k = b.colptr[j]:(b.colptr[j + 1] - 1)
i = b.rowval[k]
vals[k] = b.res[i]
end
# Store in `vals` the nonzeros of each column of the Hessian computed with color `icol`
for range_vals in b.dcolors[icol]
for k in range_vals
row = b.rowval[k]
vals[k] = b.res[row]
end
end
end
Expand Down
22 changes: 15 additions & 7 deletions src/sparse_jacobian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ struct SparseADJacobian{T, Tag, S} <: ADBackend
colptr::Vector{Int}
colors::Vector{Int}
ncolors::Int
dcolors::Dict{Int, Vector{UnitRange{Int}}}
z::Vector{ForwardDiff.Dual{Tag, T, 1}}
cz::Vector{ForwardDiff.Dual{Tag, T, 1}}
res::S
Expand Down Expand Up @@ -31,13 +32,20 @@ function SparseADJacobian(
rowval = J.rowval
colptr = J.colptr

# The indices of the nonzero elements in `vals` that will be processed by color `c` are stored in `dcolors[c]`.
dcolors = Dict(i => UnitRange{Int}[] for i=1:ncolors)
for (i, color) in enumerate(colors)
range_vals = colptr[i]:(colptr[i + 1] - 1)
push!(dcolors[color], range_vals)
end

tag = ForwardDiff.Tag{typeof(c!), T}

z = Vector{ForwardDiff.Dual{tag, T, 1}}(undef, nvar)
cz = similar(z, ncon)
res = similar(x0, ncon)

SparseADJacobian(d, rowval, colptr, colors, ncolors, z, cz, res)
SparseADJacobian(d, rowval, colptr, colors, ncolors, dcolors, z, cz, res)
end

function get_nln_nnzj(b::SparseADJacobian, nvar, ncon)
Expand Down Expand Up @@ -71,12 +79,12 @@ function sparse_jac_coord!(
map!(ForwardDiff.Dual{Tag}, b.z, x, b.d) # x + ε * v
ℓ!(b.cz, b.z) # c!(cz, x + ε * v)
ForwardDiff.extract_derivative!(Tag, b.res, b.cz) # ∇c!(cx, x)ᵀv
for j = 1:nvar
if b.colors[j] == icol
for k = b.colptr[j]:(b.colptr[j + 1] - 1)
i = b.rowval[k]
vals[k] = b.res[i]
end

# Store in `vals` the nonzeros of each column of the Jacobian computed with color `icol`
for range_vals in b.dcolors[icol]
for k in range_vals
row = b.rowval[k]
vals[k] = b.res[row]
end
end
end
Expand Down
Loading