Skip to content

Commit

Permalink
Friendly errors on array vs. scalar mistakes (#489)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
mcabbott and Michael Abbott authored Dec 28, 2020
1 parent c6f52b2 commit ec28978
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/derivative.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Set `check` to `Val{false}()` to disable tag checking. This can lead to perturba
return result
end

derivative(f, x::AbstractArray) = throw(DimensionMismatch("derivative(f, x) expects that x is a real number. Perhaps you meant gradient(f, x)?"))

#####################
# result extraction #
#####################
Expand Down
8 changes: 8 additions & 0 deletions src/gradient.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ end
@inline gradient!(result::Union{AbstractArray,DiffResult}, f, x::StaticArray, cfg::GradientConfig) = gradient!(result, f, x)
@inline gradient!(result::Union{AbstractArray,DiffResult}, f, x::StaticArray, cfg::GradientConfig, ::Val) = gradient!(result, f, x)

gradient(f, x::Real) = throw(DimensionMismatch("gradient(f, x) expects that x is an array. Perhaps you meant derivative(f, x)?"))

#####################
# result extraction #
#####################
Expand Down Expand Up @@ -91,12 +93,18 @@ function extract_gradient_chunk!(::Type{T}, result::DiffResult, dual, index, chu
return result
end

extract_gradient_chunk!(::Type, result, dual::AbstractArray, index, chunksize) = throw(GRAD_ERROR)
extract_gradient_chunk!(::Type, result::DiffResult, dual::AbstractArray, index, chunksize) = throw(GRAD_ERROR)

const GRAD_ERROR = DimensionMismatch("gradient(f, x) expects that f(x) is a real number. Perhaps you meant jacobian(f, x)?")

###############
# vector mode #
###############

function vector_mode_gradient(f::F, x, cfg::GradientConfig{T}) where {T, F}
ydual = vector_mode_dual_eval(f, x, cfg)
ydual isa Real || throw(GRAD_ERROR)
result = similar(x, valtype(ydual))
return extract_gradient!(T, result, ydual)
end
Expand Down
6 changes: 6 additions & 0 deletions src/jacobian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ end
@inline jacobian!(result::Union{AbstractArray,DiffResult}, f, x::StaticArray, cfg::JacobianConfig) = jacobian!(result, f, x)
@inline jacobian!(result::Union{AbstractArray,DiffResult}, f, x::StaticArray, cfg::JacobianConfig, ::Val) = jacobian!(result, f, x)

jacobian(f, x::Real) = throw(DimensionMismatch("jacobian(f, x) expects that x is an array. Perhaps you meant derivative(f, x)?"))

#####################
# result extraction #
#####################
Expand Down Expand Up @@ -143,6 +145,7 @@ reshape_jacobian(result::DiffResult, ydual, xdual) = reshape_jacobian(DiffResult

function vector_mode_jacobian(f::F, x, cfg::JacobianConfig{T,V,N}) where {F,T,V,N}
ydual = vector_mode_dual_eval(f, x, cfg)
ydual isa AbstractArray || throw(JACOBIAN_ERROR)
result = similar(ydual, valtype(eltype(ydual)), length(ydual), N)
extract_jacobian!(T, result, ydual, N)
extract_value!(T, result, ydual)
Expand Down Expand Up @@ -194,6 +197,8 @@ end
return result
end

const JACOBIAN_ERROR = DimensionMismatch("jacobian(f, x) expexts that f(x) is an array. Perhaps you meant gradient(f, x)?")

# chunk mode #
#------------#

Expand All @@ -216,6 +221,7 @@ function jacobian_chunk_mode_expr(work_array_definition::Expr, compute_ydual::Ex
# do first chunk manually to calculate output type
seed!(xdual, x, 1, seeds)
$(compute_ydual)
ydual isa AbstractArray || throw(JACOBIAN_ERROR)
$(result_definition)
out_reshaped = reshape_jacobian(result, ydual, xdual)
extract_jacobian_chunk!(T, out_reshaped, ydual, 1, N)
Expand Down
4 changes: 4 additions & 0 deletions test/DerivativeTest.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,8 @@ end
@test (x -> ForwardDiff.derivative(y -> x^y, 1.5))(0.0) === 0.0
end

@testset "dimension error for derivative" begin
@test_throws DimensionMismatch ForwardDiff.derivative(sum, fill(2pi, 3))
end

end # module
6 changes: 6 additions & 0 deletions test/GradientTest.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,10 @@ end
@test isempty(g_grad_const(zeros(Float64, 0)))
end

@testset "dimension errors for gradient" begin
@test_throws DimensionMismatch ForwardDiff.gradient(identity, 2pi) # input
@test_throws DimensionMismatch ForwardDiff.gradient(identity, fill(2pi, 2)) # vector_mode_gradient
@test_throws DimensionMismatch ForwardDiff.gradient(identity, fill(2pi, 10^6)) # chunk_mode_gradient
end

end # module
6 changes: 6 additions & 0 deletions test/JacobianTest.jl
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,10 @@ for T in (StaticArrays.SArray, StaticArrays.MArray)
@test DiffResults.jacobian(sresult3) == DiffResults.jacobian(result)
end

@testset "dimension errors for jacobian" begin
@test_throws DimensionMismatch ForwardDiff.jacobian(identity, 2pi) # input
@test_throws DimensionMismatch ForwardDiff.jacobian(sum, fill(2pi, 2)) # vector_mode_jacobian
@test_throws DimensionMismatch ForwardDiff.jacobian(sum, fill(2pi, 10^6)) # chunk_mode_jacobian
end

end # module

0 comments on commit ec28978

Please sign in to comment.