Skip to content

Commit

Permalink
Merge 8710981 into 50f39be
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisRackauckas committed Jan 12, 2019
2 parents 50f39be + 8710981 commit 5030c6f
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
44 changes: 44 additions & 0 deletions docs/src/user/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,47 @@ 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
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))
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,MyTag)
```

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
```
10 changes: 10 additions & 0 deletions src/dual.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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 #
##############################
Expand Down

0 comments on commit 5030c6f

Please sign in to comment.