Skip to content

Commit afa82d7

Browse files
authored
More tests for sparse Jacobians and Hessians (#189)
1 parent dfd6022 commit afa82d7

6 files changed

Lines changed: 218 additions & 31 deletions

File tree

DifferentiationInterface/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DifferentiationInterface"
22
uuid = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63"
33
authors = ["Guillaume Dalle", "Adrian Hill"]
4-
version = "0.2.0"
4+
version = "0.2.1"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"

DifferentiationInterface/ext/DifferentiationInterfaceSymbolicsExt/onearg.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ end
148148
function DI.prepare_jacobian(f, backend::AnyAutoSymbolics, x)
149149
x_var = variables(:x, axes(x)...)
150150
jac_var = if issparse(backend)
151-
sparsejacobian(f(x_var), x_var)
151+
sparsejacobian(vec(f(x_var)), vec(x_var))
152152
else
153153
jacobian(f(x_var), x_var)
154154
end
@@ -192,7 +192,7 @@ end
192192

193193
function DI.prepare_hessian(f, backend::AnyAutoSymbolics, x)
194194
x_var = variables(:x, axes(x)...)
195-
# Symbolic.gradient only accepts vectors
195+
# Symbolic.hessian only accepts vectors
196196
hess_var = if issparse(backend)
197197
sparsehessian(f(x_var), vec(x_var))
198198
else

DifferentiationInterface/ext/DifferentiationInterfaceSymbolicsExt/twoarg.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ function DI.prepare_jacobian(f!, y, backend::AnyAutoSymbolics, x)
124124
y_var = variables(:y, axes(y)...)
125125
f!(y_var, x_var)
126126
jac_var = if issparse(backend)
127-
sparsejacobian(y_var, x_var)
127+
sparsejacobian(vec(y_var), vec(x_var))
128128
else
129129
jacobian(y_var, x_var)
130130
end

DifferentiationInterface/test/sparsity.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ end
2020

2121
test_differentiation(
2222
sparse_backends,
23-
sparse_scenarios(rand(5));
23+
sparse_scenarios();
2424
sparsity=true,
2525
second_order=false,
2626
logging=get(ENV, "CI", "false") == "false",
2727
)
2828

2929
test_differentiation(
3030
sparse_second_order_backends,
31-
sparse_scenarios(rand(5));
31+
sparse_scenarios();
3232
sparsity=true,
3333
first_order=false,
3434
logging=get(ENV, "CI", "false") == "false",

DifferentiationInterfaceTest/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DifferentiationInterfaceTest"
22
uuid = "a82114a7-5aa3-49a8-9643-716bb13727a3"
33
authors = ["Guillaume Dalle", "Adrian Hill"]
4-
version = "0.2.0"
4+
version = "0.2.1"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
@@ -21,7 +21,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2121
ADTypes = "0.2.7"
2222
Chairmarks = "1.2.1"
2323
ComponentArrays = "0.15"
24-
DifferentiationInterface = "0.2.0"
24+
DifferentiationInterface = "0.2.1"
2525
DocStringExtensions = "0.9"
2626
JET = "0.8"
2727
JLArrays = "0.1"
Lines changed: 210 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,239 @@
11
## Vector to vector
22

3-
abs2diff(x) = abs2.(diff(x))
3+
diffsquare(x::AbstractVector)::AbstractVector = diff(x) .^ 2
4+
diffcube(x::AbstractVector)::AbstractVector = diff(x) .^ 3
45

5-
function abs2diff!(y, x)
6-
y .= abs2.(diff(x))
6+
function diffsquare!(y::AbstractVector, x::AbstractVector)
7+
x1 = @view x[1:(end - 1)]
8+
x2 = @view x[2:end]
9+
y .= x2 .- x1
10+
y .^= 2
711
return nothing
812
end
913

10-
function abs2diff_jacobian(x)
14+
function diffcube!(y::AbstractVector, x::AbstractVector)
15+
x1 = @view x[1:(end - 1)]
16+
x2 = @view x[2:end]
17+
y .= x2 .- x1
18+
y .^= 3
19+
return nothing
20+
end
21+
22+
function diffsquare_jacobian(x)
1123
n = length(x)
1224
return spdiagm(n - 1, n, 0 => -2 * diff(x), 1 => 2 * diff(x))
1325
end
1426

15-
## Vector to scalar
16-
17-
sumabs2diff(x) = sum(abs2diff(x))
27+
function diffcube_jacobian(x)
28+
n = length(x)
29+
return spdiagm(n - 1, n, 0 => -3 * diff(x) .^ 2, 1 => 3 * diff(x) .^ 2)
30+
end
1831

19-
function sumabs2diff_hessian(x)
20-
T = eltype(x)
32+
function sparse_vec_to_vec_scenarios(x::AbstractVector)
2133
n = length(x)
22-
return spdiagm(
23-
0 => vcat(2 * one(T), fill(4 * one(T), n - 2), 2 * one(T)),
24-
1 => fill(-2 * one(T), n - 1),
25-
-1 => fill(-2 * one(T), n - 1),
26-
)
34+
scens = AbstractScenario[]
35+
for op in (:outofplace, :inplace)
36+
append!(
37+
scens,
38+
[
39+
JacobianScenario(diffsquare; x=x, ref=diffsquare_jacobian, operator=op),
40+
JacobianScenario(
41+
diffsquare!;
42+
x=x,
43+
y=similar(x, n - 1),
44+
ref=diffsquare_jacobian,
45+
operator=op,
46+
),
47+
],
48+
)
49+
end
50+
return scens
2751
end
2852

29-
## Gather
53+
## Matrix to vector
3054

31-
"""
32-
sparse_scenarios()
55+
function diffsquarecube_matvec(x::AbstractMatrix)::AbstractVector
56+
return vcat(diffsquare(vec(x)), diffcube(vec(x)))
57+
end
3358

34-
Create a vector of [`AbstractScenario`](@ref)s with sparse array types, focused on sparse Jacobians and Hessians.
35-
"""
36-
function sparse_scenarios(x::AbstractVector)
59+
function diffsquarecube_matvec!(y::AbstractVector, x::AbstractMatrix)
60+
m, n = size(x)
61+
diffsquare!(view(y, 1:(m * n - 1)), vec(x))
62+
diffcube!(view(y, (m * n):(2(m * n) - 2)), vec(x))
63+
return nothing
64+
end
65+
66+
function diffsquarecube_matvec_jacobian(x)
67+
return vcat(diffsquare_jacobian(vec(x)), diffcube_jacobian(vec(x)))
68+
end
69+
70+
function sparse_mat_to_vec_scenarios(x::AbstractMatrix)
71+
m, n = size(x)
72+
scens = AbstractScenario[]
73+
for op in (:outofplace, :inplace)
74+
append!(
75+
scens,
76+
[
77+
JacobianScenario(
78+
diffsquarecube_matvec;
79+
x=x,
80+
ref=diffsquarecube_matvec_jacobian,
81+
operator=op,
82+
),
83+
JacobianScenario(
84+
diffsquarecube_matvec!;
85+
x=x,
86+
y=similar(x, 2(m * n) - 2),
87+
ref=diffsquarecube_matvec_jacobian,
88+
operator=op,
89+
),
90+
],
91+
)
92+
end
93+
return scens
94+
end
95+
96+
## Vector to matrix
97+
98+
diffsquarecube_vecmat(x::AbstractVector)::AbstractMatrix = hcat(diffsquare(x), diffcube(x))
99+
100+
function diffsquarecube_vecmat!(y::AbstractMatrix, x::AbstractVector)
101+
diffsquare!(view(y, :, 1), x)
102+
diffcube!(view(y, :, 2), x)
103+
return nothing
104+
end
105+
106+
function diffsquarecube_vecmat_jacobian(x::AbstractVector)
107+
return vcat(diffsquare_jacobian(x), diffcube_jacobian(x))
108+
end
109+
110+
function sparse_vec_to_mat_scenarios(x::AbstractVector)
37111
n = length(x)
38112
scens = AbstractScenario[]
39113
for op in (:outofplace, :inplace)
40114
append!(
41115
scens,
42116
[
43-
JacobianScenario(abs2diff; x=x, ref=abs2diff_jacobian, operator=op),
44117
JacobianScenario(
45-
abs2diff!; x=x, y=similar(x, n - 1), ref=abs2diff_jacobian, operator=op
118+
diffsquarecube_vecmat;
119+
x=x,
120+
ref=diffsquarecube_vecmat_jacobian,
121+
operator=op,
122+
),
123+
JacobianScenario(
124+
diffsquarecube_vecmat!;
125+
x=x,
126+
y=similar(x, n - 1, 2),
127+
ref=diffsquarecube_vecmat_jacobian,
128+
operator=op,
46129
),
47-
HessianScenario(sumabs2diff; x=x, ref=sumabs2diff_hessian, operator=op),
48130
],
49131
)
50132
end
51133
return scens
52134
end
135+
136+
## Matrix to matrix
137+
138+
function diffsquarecube_matmat(x::AbstractMatrix)::AbstractMatrix
139+
return hcat(diffsquare(vec(x)), diffcube(vec(x)))
140+
end
141+
142+
function diffsquarecube_matmat!(y::AbstractMatrix, x::AbstractMatrix)
143+
diffsquare!(view(y, :, 1), vec(x))
144+
diffcube!(view(y, :, 2), vec(x))
145+
return nothing
146+
end
147+
148+
function diffsquarecube_matmat_jacobian(x::AbstractMatrix)
149+
return vcat(diffsquare_jacobian(vec(x)), diffcube_jacobian(vec(x)))
150+
end
151+
152+
function sparse_mat_to_mat_scenarios(x::AbstractMatrix)
153+
m, n = size(x)
154+
scens = AbstractScenario[]
155+
for op in (:outofplace, :inplace)
156+
append!(
157+
scens,
158+
[
159+
JacobianScenario(
160+
diffsquarecube_matmat;
161+
x=x,
162+
ref=diffsquarecube_matmat_jacobian,
163+
operator=op,
164+
),
165+
JacobianScenario(
166+
diffsquarecube_matmat!;
167+
x=x,
168+
y=similar(x, m * n - 1, 2),
169+
ref=diffsquarecube_matmat_jacobian,
170+
operator=op,
171+
),
172+
],
173+
)
174+
end
175+
return scens
176+
end
177+
178+
## Vector to scalar
179+
180+
sumdiffcube(x::AbstractVector)::Number = sum(diffcube(x))
181+
182+
function sumdiffcube_hessian(x)
183+
T = eltype(x)
184+
d = 6 * diff(x)
185+
return spdiagm(0 => vcat(d, zero(T)) + vcat(zero(T), d), 1 => -d, -1 => -d)
186+
end
187+
188+
function sparse_vec_to_num_scenarios(x::AbstractVector)
189+
scens = AbstractScenario[]
190+
for op in (:outofplace, :inplace)
191+
append!(
192+
scens, [HessianScenario(sumdiffcube; x=x, ref=sumdiffcube_hessian, operator=op)]
193+
)
194+
end
195+
return scens
196+
end
197+
198+
## Matrix to scalar
199+
200+
sumdiffcube_mat(x::AbstractMatrix)::Number = sum(diffcube(vec(x)))
201+
202+
function sumdiffcube_mat_hessian(x::AbstractMatrix)
203+
T = eltype(x)
204+
d = 6 * diff(vec(x))
205+
return spdiagm(0 => vcat(d, zero(T)) + vcat(zero(T), d), 1 => -d, -1 => -d)
206+
end
207+
208+
function sparse_mat_to_num_scenarios(x::AbstractMatrix)
209+
scens = AbstractScenario[]
210+
for op in (:outofplace, :inplace)
211+
append!(
212+
scens,
213+
[
214+
HessianScenario(
215+
sumdiffcube_mat; x=x, ref=sumdiffcube_mat_hessian, operator=op
216+
),
217+
],
218+
)
219+
end
220+
return scens
221+
end
222+
223+
## Gather
224+
225+
"""
226+
sparse_scenarios()
227+
228+
Create a vector of [`AbstractScenario`](@ref)s with sparse array types, focused on sparse Jacobians and Hessians.
229+
"""
230+
function sparse_scenarios()
231+
return vcat(
232+
sparse_vec_to_vec_scenarios(randn(6)),
233+
sparse_vec_to_mat_scenarios(randn(6)),
234+
sparse_mat_to_vec_scenarios(randn(2, 3)),
235+
sparse_mat_to_mat_scenarios(randn(2, 3)),
236+
sparse_vec_to_num_scenarios(randn(6)),
237+
sparse_mat_to_num_scenarios(randn(2, 3)),
238+
)
239+
end

0 commit comments

Comments
 (0)