From e704b0e2dcf49694d8243d6029323517b1a682cd Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Sat, 12 Jan 2019 04:45:01 -0800 Subject: [PATCH 1/5] Document manual Dual number seeding and add seed_duals convenience --- docs/src/user/advanced.md | 35 +++++++++++++++++++++++++++++++++++ src/dual.jl | 10 ++++++++++ 2 files changed, 45 insertions(+) diff --git a/docs/src/user/advanced.md b/docs/src/user/advanced.md index 8ff07758..dfee777e 100644 --- a/docs/src/user/advanced.md +++ b/docs/src/user/advanced.md @@ -232,3 +232,38 @@ want to disable this checking. cfg = GradientConfig(nothing, x) gradient(f, x, cfg) ``` + +## Manually Seeding Dual Numbers + +In some cases you may want to manually seed the `Dual` numbers and directly +send these to a function. This can be useful for example if said function does +not return a scalar or vector but still has a useful interpretation of a derivative. + +Let's say we had a vector `x=[1.0,1.5,3.0,1.0]` and wanted to take the derivative +of some algorithm with respect to each value. Since we are taking 4 different +derivatives, we will have 4 separate partials. For each partial, we seed a +`1.0` at the source of the value, and a zero everywhere else. The Dual seeded +version of this vector would thus be: + +```julia +using ForwardDiff: Dual +x1dual = Dual{MyTag}(1.0, (1.0, 0.0, 0.0, 0.0)) +x2dual = Dual{MyTag}(1.5, (0.0, 1.0, 0.0, 0.0)) +x3dual = Dual{MyTag}(3.0, (0.0, 0.0, 1.0, 0.0)) +x4dual = Dual{MyTag}(1.0, (0.0, 0.0, 0.0, 0.0)) +xdual = [x1dual, x2dual, x3dual, x4dual] +``` + +Calculations using `xdual` instead of `x` will result in `Dual` numbers and the +partial terms will be the derivative with respect to `x[i]`. Most conversions +will happen automatically, but you may need to convert other inputs into the +function to zero-seeded duals, and this can be done by simply calling +`convert(eltype(p),y)` on a scalar `y` (or broadcasting this conversion). + +As a convenience, to seed a vector with unique partials for the size of the +vector you can use the `seed_duals` function. Thus the following is equivalent +to the code above: + +```julia +xdual = ForwardDiff.seed_duals(x) +``` diff --git a/src/dual.jl b/src/dual.jl index bb4df73f..75d9f6df 100644 --- a/src/dual.jl +++ b/src/dual.jl @@ -73,6 +73,16 @@ end @inline Dual{T,V,N}(x::Number) where {T,V,N} = convert(Dual{T,V,N}, x) @inline Dual{T,V}(x) where {T,V} = convert(Dual{T,V}, x) +############################ +# Convenience Constructors # +############################ + +function seed_duals(x::AbstractArray{V},::Type{T}, + ::Chunk{N} = Chunk(x)) where {V,T,N} + seeds = construct_seeds(Partials{N,V}) + duals = [Dual{T}(x[i],seeds[i]) for i in 1:length(x)] +end + ############################## # Utility/Accessor Functions # ############################## From 705a0960662e0f4815e3e86aed6add288eff622f Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Sat, 12 Jan 2019 04:48:28 -0800 Subject: [PATCH 2/5] add interpretation of resulting Dual numbers --- docs/src/user/advanced.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/src/user/advanced.md b/docs/src/user/advanced.md index dfee777e..ae145ea3 100644 --- a/docs/src/user/advanced.md +++ b/docs/src/user/advanced.md @@ -267,3 +267,11 @@ to the code above: ```julia xdual = ForwardDiff.seed_duals(x) ``` + +After the calculations are done, the value and derivative of the calculation +can be extracted using the following: + +```julia +y.value # Returns the value, i.e. what would've been produced without Duals +y.partials[i] # Returns the derivative of the value w.r.t. the ith variable +``` From 8710981ba0b5da7c876c0f1f196b947d15ec9314 Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Sat, 12 Jan 2019 04:52:34 -0800 Subject: [PATCH 3/5] remember to pass a tag to seed_duals --- docs/src/user/advanced.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/user/advanced.md b/docs/src/user/advanced.md index ae145ea3..ebf2c65d 100644 --- a/docs/src/user/advanced.md +++ b/docs/src/user/advanced.md @@ -247,6 +247,7 @@ version of this vector would thus be: ```julia using ForwardDiff: Dual +struct MyTag end # Unique tag for the Duals x1dual = Dual{MyTag}(1.0, (1.0, 0.0, 0.0, 0.0)) x2dual = Dual{MyTag}(1.5, (0.0, 1.0, 0.0, 0.0)) x3dual = Dual{MyTag}(3.0, (0.0, 0.0, 1.0, 0.0)) @@ -265,7 +266,7 @@ vector you can use the `seed_duals` function. Thus the following is equivalent to the code above: ```julia -xdual = ForwardDiff.seed_duals(x) +xdual = ForwardDiff.seed_duals(x,MyTag) ``` After the calculations are done, the value and derivative of the calculation From 84af784679a5d03e253e5b92e0a7c04730776bc6 Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Sat, 15 Jun 2019 03:22:53 -0400 Subject: [PATCH 4/5] Update advanced.md --- docs/src/user/advanced.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/user/advanced.md b/docs/src/user/advanced.md index ebf2c65d..0e4e8b75 100644 --- a/docs/src/user/advanced.md +++ b/docs/src/user/advanced.md @@ -251,7 +251,7 @@ struct MyTag end # Unique tag for the Duals x1dual = Dual{MyTag}(1.0, (1.0, 0.0, 0.0, 0.0)) x2dual = Dual{MyTag}(1.5, (0.0, 1.0, 0.0, 0.0)) x3dual = Dual{MyTag}(3.0, (0.0, 0.0, 1.0, 0.0)) -x4dual = Dual{MyTag}(1.0, (0.0, 0.0, 0.0, 0.0)) +x4dual = Dual{MyTag}(1.0, (0.0, 0.0, 0.0, 1.0)) xdual = [x1dual, x2dual, x3dual, x4dual] ``` From 45369023da7115941ec09e71a13e36e6bdada313 Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Sun, 31 Dec 2023 09:20:05 -0500 Subject: [PATCH 5/5] Update src/dual.jl Co-authored-by: Yuto Horikawa --- src/dual.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dual.jl b/src/dual.jl index 75d9f6df..f9164a80 100644 --- a/src/dual.jl +++ b/src/dual.jl @@ -79,8 +79,8 @@ end function seed_duals(x::AbstractArray{V},::Type{T}, ::Chunk{N} = Chunk(x)) where {V,T,N} - seeds = construct_seeds(Partials{N,V}) - duals = [Dual{T}(x[i],seeds[i]) for i in 1:length(x)] + seeds = construct_seeds(Partials{N,V}) + duals = [Dual{T}(x[i],seeds[i]) for i in eachindex(x)] end ##############################