Skip to content

Commit ec28978

Browse files
mcabbottMichael Abbott
andauthored
Friendly errors on array vs. scalar mistakes (#489)
* friendly errors for output type f(x) * friendly errors on input type * change error type, fix jacobian * add tests * spelling + wording Co-authored-by: Michael Abbott <me@escbook>
1 parent c6f52b2 commit ec28978

File tree

6 files changed

+32
-0
lines changed

6 files changed

+32
-0
lines changed

src/derivative.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Set `check` to `Val{false}()` to disable tag checking. This can lead to perturba
6969
return result
7070
end
7171

72+
derivative(f, x::AbstractArray) = throw(DimensionMismatch("derivative(f, x) expects that x is a real number. Perhaps you meant gradient(f, x)?"))
73+
7274
#####################
7375
# result extraction #
7476
#####################

src/gradient.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ end
4949
@inline gradient!(result::Union{AbstractArray,DiffResult}, f, x::StaticArray, cfg::GradientConfig) = gradient!(result, f, x)
5050
@inline gradient!(result::Union{AbstractArray,DiffResult}, f, x::StaticArray, cfg::GradientConfig, ::Val) = gradient!(result, f, x)
5151

52+
gradient(f, x::Real) = throw(DimensionMismatch("gradient(f, x) expects that x is an array. Perhaps you meant derivative(f, x)?"))
53+
5254
#####################
5355
# result extraction #
5456
#####################
@@ -91,12 +93,18 @@ function extract_gradient_chunk!(::Type{T}, result::DiffResult, dual, index, chu
9193
return result
9294
end
9395

96+
extract_gradient_chunk!(::Type, result, dual::AbstractArray, index, chunksize) = throw(GRAD_ERROR)
97+
extract_gradient_chunk!(::Type, result::DiffResult, dual::AbstractArray, index, chunksize) = throw(GRAD_ERROR)
98+
99+
const GRAD_ERROR = DimensionMismatch("gradient(f, x) expects that f(x) is a real number. Perhaps you meant jacobian(f, x)?")
100+
94101
###############
95102
# vector mode #
96103
###############
97104

98105
function vector_mode_gradient(f::F, x, cfg::GradientConfig{T}) where {T, F}
99106
ydual = vector_mode_dual_eval(f, x, cfg)
107+
ydual isa Real || throw(GRAD_ERROR)
100108
result = similar(x, valtype(ydual))
101109
return extract_gradient!(T, result, ydual)
102110
end

src/jacobian.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ end
9090
@inline jacobian!(result::Union{AbstractArray,DiffResult}, f, x::StaticArray, cfg::JacobianConfig) = jacobian!(result, f, x)
9191
@inline jacobian!(result::Union{AbstractArray,DiffResult}, f, x::StaticArray, cfg::JacobianConfig, ::Val) = jacobian!(result, f, x)
9292

93+
jacobian(f, x::Real) = throw(DimensionMismatch("jacobian(f, x) expects that x is an array. Perhaps you meant derivative(f, x)?"))
94+
9395
#####################
9496
# result extraction #
9597
#####################
@@ -143,6 +145,7 @@ reshape_jacobian(result::DiffResult, ydual, xdual) = reshape_jacobian(DiffResult
143145

144146
function vector_mode_jacobian(f::F, x, cfg::JacobianConfig{T,V,N}) where {F,T,V,N}
145147
ydual = vector_mode_dual_eval(f, x, cfg)
148+
ydual isa AbstractArray || throw(JACOBIAN_ERROR)
146149
result = similar(ydual, valtype(eltype(ydual)), length(ydual), N)
147150
extract_jacobian!(T, result, ydual, N)
148151
extract_value!(T, result, ydual)
@@ -194,6 +197,8 @@ end
194197
return result
195198
end
196199

200+
const JACOBIAN_ERROR = DimensionMismatch("jacobian(f, x) expexts that f(x) is an array. Perhaps you meant gradient(f, x)?")
201+
197202
# chunk mode #
198203
#------------#
199204

@@ -216,6 +221,7 @@ function jacobian_chunk_mode_expr(work_array_definition::Expr, compute_ydual::Ex
216221
# do first chunk manually to calculate output type
217222
seed!(xdual, x, 1, seeds)
218223
$(compute_ydual)
224+
ydual isa AbstractArray || throw(JACOBIAN_ERROR)
219225
$(result_definition)
220226
out_reshaped = reshape_jacobian(result, ydual, xdual)
221227
extract_jacobian_chunk!(T, out_reshaped, ydual, 1, N)

test/DerivativeTest.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,8 @@ end
9696
@test (x -> ForwardDiff.derivative(y -> x^y, 1.5))(0.0) === 0.0
9797
end
9898

99+
@testset "dimension error for derivative" begin
100+
@test_throws DimensionMismatch ForwardDiff.derivative(sum, fill(2pi, 3))
101+
end
102+
99103
end # module

test/GradientTest.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,10 @@ end
156156
@test isempty(g_grad_const(zeros(Float64, 0)))
157157
end
158158

159+
@testset "dimension errors for gradient" begin
160+
@test_throws DimensionMismatch ForwardDiff.gradient(identity, 2pi) # input
161+
@test_throws DimensionMismatch ForwardDiff.gradient(identity, fill(2pi, 2)) # vector_mode_gradient
162+
@test_throws DimensionMismatch ForwardDiff.gradient(identity, fill(2pi, 10^6)) # chunk_mode_gradient
163+
end
164+
159165
end # module

test/JacobianTest.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,10 @@ for T in (StaticArrays.SArray, StaticArrays.MArray)
225225
@test DiffResults.jacobian(sresult3) == DiffResults.jacobian(result)
226226
end
227227

228+
@testset "dimension errors for jacobian" begin
229+
@test_throws DimensionMismatch ForwardDiff.jacobian(identity, 2pi) # input
230+
@test_throws DimensionMismatch ForwardDiff.jacobian(sum, fill(2pi, 2)) # vector_mode_jacobian
231+
@test_throws DimensionMismatch ForwardDiff.jacobian(sum, fill(2pi, 10^6)) # chunk_mode_jacobian
232+
end
233+
228234
end # module

0 commit comments

Comments
 (0)