Repository: JuliaDiff/FiniteDifferences.jl (julia)

Issue:
j′vp errors on empty array primal input
`j′vp` errors when the primal input is an empty array, while `jvp` works fine. Here's an MWE:

```julia
julia> foo(x) = isempty(x) ? zero(eltype(x)) : first(x)
foo (generic function with 1 method)

julia> foo(Float64[])
0.0

julia> jvp(central_fdm(5, 1), foo, (Float64[], Float64[]))
0.0

julia> j′vp(central_fdm(5, 1), foo, 1.0, Float64[])
ERROR: DimensionMismatch("")
Stacktrace:
 [1] *(::Transpose{Any,Array{Any,1}}, ::Array{Float64,1}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.4/LinearAlgebra/src/adjtrans.jl:249
 [2] _j′vp(::FiniteDifferences.Central{UnitRange{Int64},Array{Float64,1}}, ::Function, ::Array{Float64,1}, ::Array{Float64,1}) at /Users/saxen/.julia/packages/FiniteDifferences/0ACfA/src/grad.jl:79
 [3] j′vp(::FiniteDifferences.Central{UnitRange{Int64},Array{Float64,1}}, ::Function, ::Float64, ::Array{Float64,1}) at /Users/saxen/.julia/packages/FiniteDifferences/0ACfA/src/grad.jl:73
 [4] top-level scope at REPL[9]:1

```

Pull request description:
The Jacobian for a function with an empty primal will be `Any[]` regardless of the function, which can't be multiplied by the cotangent on the output. This PR fixes #92 by detecting an empty primal and returning an empty cotangent with the same eltype as that of the cotangent of the output.

Patch:
diff --git a/Project.toml b/Project.toml
index a00e73c2..06f6ced5 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,6 +1,6 @@
 name = "FiniteDifferences"
 uuid = "26cc04aa-876d-5657-8c51-4c34ba976000"
-version = "0.10.3"
+version = "0.10.4"
 
 [deps]
 LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
diff --git a/src/grad.jl b/src/grad.jl
index 673aeb34..f02f849b 100644
--- a/src/grad.jl
+++ b/src/grad.jl
@@ -76,6 +76,7 @@ end
 j′vp(fdm, f, ȳ, xs...) = j′vp(fdm, xs->f(xs...), ȳ, xs)[1]
 
 function _j′vp(fdm, f, ȳ::Vector{<:Real}, x::Vector{<:Real})
+    isempty(x) && return eltype(ȳ)[] # if x is empty, then so is the jacobian and x̄
     return transpose(first(jacobian(fdm, f, x))) * ȳ
 end
 


Test patch:
diff --git a/test/grad.jl b/test/grad.jl
index 1bdaf953..29beee2d 100644
--- a/test/grad.jl
+++ b/test/grad.jl
@@ -140,15 +140,17 @@ using FiniteDifferences: grad, jacobian, _jvp, jvp, j′vp, _j′vp, to_vec
     end
 
     @testset "j′vp(::$T)" for T in (Float64,)
-        rng, N, M, fdm = MersenneTwister(123456), 2, 3, central_fdm(5, 1)
-        x, y = randn(rng, T, N), randn(rng, T, M)
-        z̄ = randn(rng, T, N + M)
-        xy = vcat(x, y)
-        x̄ȳ_manual = j′vp(fdm, xy->sin.(xy), z̄, xy)[1]
-        x̄ȳ_auto = j′vp(fdm, x->sin.(vcat(x[1], x[2])), z̄, (x, y))[1]
-        x̄ȳ_multi = j′vp(fdm, (x, y)->sin.(vcat(x, y)), z̄, x, y)
-        @test x̄ȳ_manual ≈ vcat(x̄ȳ_auto...)
-        @test x̄ȳ_manual ≈ vcat(x̄ȳ_multi...)
+        rng, fdm = MersenneTwister(123456), central_fdm(5, 1)
+        @testset "x with length $N, y with length $M" for (N, M) in ((2, 3), (0, 0), (0, 3))
+            x, y = randn(rng, T, N), randn(rng, T, M)
+            z̄ = randn(rng, T, N + M)
+            xy = vcat(x, y)
+            x̄ȳ_manual = j′vp(fdm, xy->sin.(xy), z̄, xy)[1]
+            x̄ȳ_auto = j′vp(fdm, x->sin.(vcat(x[1], x[2])), z̄, (x, y))[1]
+            x̄ȳ_multi = j′vp(fdm, (x, y)->sin.(vcat(x, y)), z̄, x, y)
+            @test x̄ȳ_manual ≈ vcat(x̄ȳ_auto...)
+            @test x̄ȳ_manual ≈ vcat(x̄ȳ_multi...)
+        end
     end
 
     # Tests for complex numbers, to prevent regressions against