ForwardDiff.jl icon indicating copy to clipboard operation
ForwardDiff.jl copied to clipboard

Forbid offsets

Open mcabbott opened this issue 3 years ago • 2 comments

This follows LinearAlgebra in explicitly forbidding offset arrays. They don't work anyway, but this replaces a BoundsError with something deliberate:

julia> ForwardDiff.gradient(sum, OffsetArray([1,2,3], 3))  # before
ERROR: BoundsError: attempt to access 3-element OffsetArray(::Vector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}}, 4:6) with eltype Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3} with indices 4:6 at index [1:3]
Stacktrace:
  [1] throw_boundserror(A::OffsetVector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}, Vector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}}}, I::Tuple{UnitRange{Int64}})
    @ Base ./abstractarray.jl:703
  [2] checkbounds
    @ ./abstractarray.jl:668 [inlined]
  [3] view
    @ ./subarray.jl:177 [inlined]
  [4] maybeview
    @ ./views.jl:148 [inlined]
  [5] dotview
    @ ./broadcast.jl:1201 [inlined]
  [6] seed!(duals::OffsetVector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}, Vector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}}}, x::OffsetVector{Int64, Vector{Int64}}, seeds::Tuple{ForwardDiff.Partials{3, Int64}, ForwardDiff.Partials{3, Int64}, ForwardDiff.Partials{3, Int64}})
    @ ForwardDiff ~/.julia/dev/ForwardDiff/src/apiutils.jl:65
  [7] vector_mode_dual_eval!
    @ ~/.julia/dev/ForwardDiff/src/apiutils.jl:36 [inlined]
  [8] vector_mode_gradient(f::typeof(sum), x::OffsetVector{Int64, Vector{Int64}}, cfg::ForwardDiff.GradientConfig{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3, OffsetVector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}, Vector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}}}})
    @ ForwardDiff ~/.julia/dev/ForwardDiff/src/gradient.jl:106
  [9] gradient(f::Function, x::OffsetVector{Int64, Vector{Int64}}, cfg::ForwardDiff.GradientConfig{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3, OffsetVector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}, Vector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}}}}, ::Val{true})
    @ ForwardDiff ~/.julia/dev/ForwardDiff/src/gradient.jl:0
 [10] gradient(f::Function, x::OffsetVector{Int64, Vector{Int64}}, cfg::ForwardDiff.GradientConfig{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3, OffsetVector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}, Vector{Dual{ForwardDiff.Tag{typeof(sum), Int64}, Int64, 3}}}}) (repeats 2 times)
    @ ForwardDiff ~/.julia/dev/ForwardDiff/src/gradient.jl:17
 [11] top-level scope
    @ REPL[162]:1

julia> ForwardDiff.gradient(sum, OffsetArray([1,2,3], 3))  # after
ERROR: ArgumentError: offset arrays are not supported but got an array with index other than 1

mcabbott avatar May 17 '22 03:05 mcabbott

I think it would be better to put the checks in the functions that assume one-based indexing https://github.com/JuliaDiff/ForwardDiff.jl/blob/78c73afd9a21593daf54f61c7d0db67130cf29e1/src/apiutils.jl#L62-L84 where the error you show is thrown from. Or maybe just change the indexing to be generic?

andreasnoack avatar Aug 04 '22 19:08 andreasnoack

My hope is that eventually general indexing could be supported, and these checks can be removed as soon as there are tests that it works.

I didn't bother to figure out precisely where the failures were, but did check that all the functions to which this error was added do currently fail.

mcabbott avatar Aug 04 '22 21:08 mcabbott