From 41c97e67944dc3fc5429039b9be7440f381ac3b2 Mon Sep 17 00:00:00 2001 From: Michael Abbott <32575566+mcabbott@users.noreply.github.com> Date: Mon, 16 May 2022 22:58:00 -0400 Subject: [PATCH 1/3] no offsets --- src/derivative.jl | 3 +++ src/gradient.jl | 2 ++ src/hessian.jl | 3 +++ src/jacobian.jl | 4 ++++ src/prelude.jl | 6 ++++++ 5 files changed, 18 insertions(+) diff --git a/src/derivative.jl b/src/derivative.jl index 5d7e5dab..17468d68 100644 --- a/src/derivative.jl +++ b/src/derivative.jl @@ -24,6 +24,7 @@ Set `check` to `Val{false}()` to disable tag checking. This can lead to perturba """ @inline function derivative(f!, y::AbstractArray, x::Real, cfg::DerivativeConfig{T} = DerivativeConfig(f!, y, x), ::Val{CHK}=Val{true}()) where {T, CHK} + require_one_based_indexing(y) CHK && checktag(T, f!, x) ydual = cfg.duals seed!(ydual, y) @@ -42,6 +43,7 @@ This method assumes that `isa(f(x), Union{Real,AbstractArray})`. """ @inline function derivative!(result::Union{AbstractArray,DiffResult}, f::F, x::R) where {F,R<:Real} + require_one_based_indexing(result) T = typeof(Tag(f, R)) ydual = f(Dual{T}(x, one(x))) result = extract_value!(T, result, ydual) @@ -60,6 +62,7 @@ Set `check` to `Val{false}()` to disable tag checking. This can lead to perturba @inline function derivative!(result::Union{AbstractArray,DiffResult}, f!, y::AbstractArray, x::Real, cfg::DerivativeConfig{T} = DerivativeConfig(f!, y, x), ::Val{CHK}=Val{true}()) where {T, CHK} + require_one_based_indexing(result, y) CHK && checktag(T, f!, x) ydual = cfg.duals seed!(ydual, y) diff --git a/src/gradient.jl b/src/gradient.jl index f9f173eb..db37411e 100644 --- a/src/gradient.jl +++ b/src/gradient.jl @@ -14,6 +14,7 @@ This method assumes that `isa(f(x), Real)`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function gradient(f, x::AbstractArray, cfg::GradientConfig{T} = GradientConfig(f, x), ::Val{CHK}=Val{true}()) where {T, CHK} + require_one_based_indexing(x) CHK && checktag(T, f, x) if chunksize(cfg) == length(x) return vector_mode_gradient(f, x, cfg) @@ -32,6 +33,7 @@ This method assumes that `isa(f(x), Real)`. """ function gradient!(result::Union{AbstractArray,DiffResult}, f::F, x::AbstractArray, cfg::GradientConfig{T} = GradientConfig(f, x), ::Val{CHK}=Val{true}()) where {T, CHK, F} + require_one_based_indexing(result, x) CHK && checktag(T, f, x) if chunksize(cfg) == length(x) vector_mode_gradient!(result, f, x, cfg) diff --git a/src/hessian.jl b/src/hessian.jl index 7de6109d..72ffbcde 100644 --- a/src/hessian.jl +++ b/src/hessian.jl @@ -12,6 +12,7 @@ This method assumes that `isa(f(x), Real)`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function hessian(f, x::AbstractArray, cfg::HessianConfig{T} = HessianConfig(f, x), ::Val{CHK}=Val{true}()) where {T,CHK} + require_one_based_indexing(x) CHK && checktag(T, f, x) ∇f = y -> gradient(f, y, cfg.gradient_config, Val{false}()) return jacobian(∇f, x, cfg.jacobian_config, Val{false}()) @@ -28,6 +29,7 @@ This method assumes that `isa(f(x), Real)`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function hessian!(result::AbstractArray, f, x::AbstractArray, cfg::HessianConfig{T} = HessianConfig(f, x), ::Val{CHK}=Val{true}()) where {T,CHK} + require_one_based_indexing(result, x) CHK && checktag(T, f, x) ∇f = y -> gradient(f, y, cfg.gradient_config, Val{false}()) jacobian!(result, ∇f, x, cfg.jacobian_config, Val{false}()) @@ -62,6 +64,7 @@ because `isa(result, DiffResult)`, `cfg` is constructed as `HessianConfig(f, res Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function hessian!(result::DiffResult, f, x::AbstractArray, cfg::HessianConfig{T} = HessianConfig(f, result, x), ::Val{CHK}=Val{true}()) where {T,CHK} + require_one_based_indexing(x) CHK && checktag(T, f, x) ∇f! = InnerGradientForHess(result, cfg, f) jacobian!(DiffResults.hessian(result), ∇f!, DiffResults.gradient(result), x, cfg.jacobian_config, Val{false}()) diff --git a/src/jacobian.jl b/src/jacobian.jl index bcda61d7..c6a046a0 100644 --- a/src/jacobian.jl +++ b/src/jacobian.jl @@ -16,6 +16,7 @@ This method assumes that `isa(f(x), AbstractArray)`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function jacobian(f, x::AbstractArray, cfg::JacobianConfig{T} = JacobianConfig(f, x), ::Val{CHK}=Val{true}()) where {T,CHK} + require_one_based_indexing(x) CHK && checktag(T, f, x) if chunksize(cfg) == length(x) return vector_mode_jacobian(f, x, cfg) @@ -33,6 +34,7 @@ stored in `y`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function jacobian(f!, y::AbstractArray, x::AbstractArray, cfg::JacobianConfig{T} = JacobianConfig(f!, y, x), ::Val{CHK}=Val{true}()) where {T, CHK} + require_one_based_indexing(y, x) CHK && checktag(T, f!, x) if chunksize(cfg) == length(x) return vector_mode_jacobian(f!, y, x, cfg) @@ -53,6 +55,7 @@ This method assumes that `isa(f(x), AbstractArray)`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function jacobian!(result::Union{AbstractArray,DiffResult}, f, x::AbstractArray, cfg::JacobianConfig{T} = JacobianConfig(f, x), ::Val{CHK}=Val{true}()) where {T, CHK} + require_one_based_indexing(result, x) CHK && checktag(T, f, x) if chunksize(cfg) == length(x) vector_mode_jacobian!(result, f, x, cfg) @@ -73,6 +76,7 @@ This method assumes that `isa(f(x), AbstractArray)`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function jacobian!(result::Union{AbstractArray,DiffResult}, f!, y::AbstractArray, x::AbstractArray, cfg::JacobianConfig{T} = JacobianConfig(f!, y, x), ::Val{CHK}=Val{true}()) where {T,CHK} + require_one_based_indexing(result, y, x) CHK && checktag(T, f!, x) if chunksize(cfg) == length(x) vector_mode_jacobian!(result, f!, y, x, cfg) diff --git a/src/prelude.jl b/src/prelude.jl index 51643339..5e753faa 100644 --- a/src/prelude.jl +++ b/src/prelude.jl @@ -70,3 +70,9 @@ function qualified_cse!(expr) end return cse_expr end + +# This allows us to call `Base.require_one_based_indexing` in `gradient!` etc: +Base.has_offset_axes(::DiffResults.DiffResult) = false +# And this is only needed for VERSION < v"1.2" +require_one_based_indexing(A...) = !Base.has_offset_axes(A...) || throw(ArgumentError( + "offset arrays are not supported but got an array with index other than 1")) From 3ba2b6af3ee282384e96944fb0f5e569a1fc3947 Mon Sep 17 00:00:00 2001 From: Michael Abbott <32575566+mcabbott@users.noreply.github.com> Date: Sun, 11 Dec 2022 23:46:19 -0500 Subject: [PATCH 2/3] ... and no piracy --- src/derivative.jl | 4 ++-- src/gradient.jl | 2 +- src/jacobian.jl | 4 ++-- src/prelude.jl | 6 ------ 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/derivative.jl b/src/derivative.jl index 17468d68..accc2405 100644 --- a/src/derivative.jl +++ b/src/derivative.jl @@ -43,7 +43,7 @@ This method assumes that `isa(f(x), Union{Real,AbstractArray})`. """ @inline function derivative!(result::Union{AbstractArray,DiffResult}, f::F, x::R) where {F,R<:Real} - require_one_based_indexing(result) + result isa DiffResult || require_one_based_indexing(result) T = typeof(Tag(f, R)) ydual = f(Dual{T}(x, one(x))) result = extract_value!(T, result, ydual) @@ -62,7 +62,7 @@ Set `check` to `Val{false}()` to disable tag checking. This can lead to perturba @inline function derivative!(result::Union{AbstractArray,DiffResult}, f!, y::AbstractArray, x::Real, cfg::DerivativeConfig{T} = DerivativeConfig(f!, y, x), ::Val{CHK}=Val{true}()) where {T, CHK} - require_one_based_indexing(result, y) + result isa DiffResult ? require_one_based_indexing(y) : require_one_based_indexing(result, y) CHK && checktag(T, f!, x) ydual = cfg.duals seed!(ydual, y) diff --git a/src/gradient.jl b/src/gradient.jl index db37411e..e5eac003 100644 --- a/src/gradient.jl +++ b/src/gradient.jl @@ -33,7 +33,7 @@ This method assumes that `isa(f(x), Real)`. """ function gradient!(result::Union{AbstractArray,DiffResult}, f::F, x::AbstractArray, cfg::GradientConfig{T} = GradientConfig(f, x), ::Val{CHK}=Val{true}()) where {T, CHK, F} - require_one_based_indexing(result, x) + result isa DiffResult ? require_one_based_indexing(x) : require_one_based_indexing(result, x) CHK && checktag(T, f, x) if chunksize(cfg) == length(x) vector_mode_gradient!(result, f, x, cfg) diff --git a/src/jacobian.jl b/src/jacobian.jl index c6a046a0..1d3fc368 100644 --- a/src/jacobian.jl +++ b/src/jacobian.jl @@ -55,7 +55,7 @@ This method assumes that `isa(f(x), AbstractArray)`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function jacobian!(result::Union{AbstractArray,DiffResult}, f, x::AbstractArray, cfg::JacobianConfig{T} = JacobianConfig(f, x), ::Val{CHK}=Val{true}()) where {T, CHK} - require_one_based_indexing(result, x) + result isa DiffResult ? require_one_based_indexing(x) : require_one_based_indexing(result, x) CHK && checktag(T, f, x) if chunksize(cfg) == length(x) vector_mode_jacobian!(result, f, x, cfg) @@ -76,7 +76,7 @@ This method assumes that `isa(f(x), AbstractArray)`. Set `check` to `Val{false}()` to disable tag checking. This can lead to perturbation confusion, so should be used with care. """ function jacobian!(result::Union{AbstractArray,DiffResult}, f!, y::AbstractArray, x::AbstractArray, cfg::JacobianConfig{T} = JacobianConfig(f!, y, x), ::Val{CHK}=Val{true}()) where {T,CHK} - require_one_based_indexing(result, y, x) + result isa DiffResult ? require_one_based_indexing(y, x) : require_one_based_indexing(result, y, x) CHK && checktag(T, f!, x) if chunksize(cfg) == length(x) vector_mode_jacobian!(result, f!, y, x, cfg) diff --git a/src/prelude.jl b/src/prelude.jl index 5e753faa..51643339 100644 --- a/src/prelude.jl +++ b/src/prelude.jl @@ -70,9 +70,3 @@ function qualified_cse!(expr) end return cse_expr end - -# This allows us to call `Base.require_one_based_indexing` in `gradient!` etc: -Base.has_offset_axes(::DiffResults.DiffResult) = false -# And this is only needed for VERSION < v"1.2" -require_one_based_indexing(A...) = !Base.has_offset_axes(A...) || throw(ArgumentError( - "offset arrays are not supported but got an array with index other than 1")) From ea88705972b04cc533fdb40ecd7ddb77e43dd810 Mon Sep 17 00:00:00 2001 From: Michael Abbott <32575566+mcabbott@users.noreply.github.com> Date: Tue, 13 Dec 2022 09:28:24 -0500 Subject: [PATCH 3/3] import from Base --- src/ForwardDiff.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ForwardDiff.jl b/src/ForwardDiff.jl index 93d3b246..d0bd6dab 100644 --- a/src/ForwardDiff.jl +++ b/src/ForwardDiff.jl @@ -8,7 +8,7 @@ if VERSION >= v"1.6" end using Random using LinearAlgebra - +using Base: require_one_based_indexing import Printf import NaNMath import SpecialFunctions