# Taking a derivative of nested object using lens from Setfield.jl

**URL:** https://discourse.julialang.org/t/taking-a-derivative-of-nested-object-using-lens-from-setfield-jl/20078
**Category:** General Usage
**Created:** [January 25, 2019, 10:28am UTC](https://discourse.julialang.org/t/taking-a-derivative-of-nested-object-using-lens-from-setfield-jl/20078 "2019-01-25T10:28:51Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)
#### Post date: [January 25, 2019, 10:28am UTC](https://discourse.julialang.org/t/taking-a-derivative-of-nested-object-using-lens-from-setfield-jl/20078/1 "2019-01-25T10:28:51Z")

</div>

This is my response to @ChrisRackauckas’s [comment](https://discourse.julialang.org/t/new-package-pseudoarclengthcontinuation/20028/10):

> [@New Package PseudoArcLengthContinuation](https://discourse.julialang.org/t/new-package-pseudoarclengthcontinuation/20028/10):
>
> > I suggest using [`Setfield.Lens`](https://jw3126.github.io/Setfield.jl/latest/index.html#Setfield.Lens) for specifying the bifurcation parameters. It’s a very handy way to make virtually any Julia object “differentiable” using ForwardDiff. Or maybe I can just pull out that part from my code.
> 
> I’m not sure what you mean here. Example?

in [New Package PseudoArcLengthContinuation](https://discourse.julialang.org/t/new-package-pseudoarclengthcontinuation/20028). I don’t want to hijack the package announcement topic of @rveltz’s awesome package [PseudoArcLengthContinuation.jl](https://rveltz.github.io/PseudoArcLengthContinuation.jl/dev/). So I’m opening a new topic.

* * *

Here is a toy example showing that you can take derivative w.r.t a “deep location” in a nested Julia object.

```julia
using Setfield
using Parameters
import ForwardDiff

xyz = (x = 1.0, y = 1.0, z = 1.0)
pair = (xyz, (x = -1.0, y = -1.0, z = -1.0))

function f(xyz)
    @unpack x, y, z = xyz
    return x^2 + y^2 + z^2
end

function g(pair)
    a, b = pair
    return f((x = a.x - b.x,
              y = a.y - b.y,
              z = a.z - b.z))
end

# Basic lens usage:
lens_x = @lens _.x
lens_1 = @lens _[1]
lens_2 = @lens _[2]

@assert pair[1].x ==
    get(pair, @lens _[1].x) ==
    get(pair, lens_1 ∘ lens_x)

@assert set(pair, lens_1 ∘ lens_x, "new value") ==
    ((x = "new value", y = 1.0, z = 1.0), pair[2])

# We can take a derivative w.r.t. a lens:
derivative(f, at, wrt::Lens) =
    ForwardDiff.derivative(
        (x) -> f(set(at, wrt, x)),
        get(at, wrt))

@assert derivative(f, xyz, lens_x) ≈ 2
@assert derivative(f, (@set xyz.x = 2.0), lens_x) ≈ 4

@assert derivative(g, pair, lens_1 ∘ lens_x) ≈ 4
@assert derivative(g, pair, lens_2 ∘ lens_x) ≈ -4

```

The last examples show that we can take derivative w.r.t. a nested value. They also show that how to specify the “location” of the nested value can be composed, like `lens_1 ∘ lens_x`.

Some detail: I said “virtually any Julia object” but actually that was exaggeration (sorry). The locations specified by the lenses have to be able to change the corresponding type parameter for this to work. This is because you need to temporary store `Dual` instead of (say) `Float64`. Also, in terms of performance, those objects probably have to be immutable to avoid heap allocation.

* * *

Now imagine that you have some ODEs and also a composite one which couples them in some way (omitting type parameters):

```julia
struct ModelA
    alpha
    beta
    ...
end

struct ModelB
    ...
end

struct CoupledModel
    A::ModelA
    B::ModelB
end

```

Then you can specify the bifurcation parameter for `ModelA` like `@lens _.alpha` and for `CoupledModel` like `@lens _.A.alpha`. Functions working with `CoupledModel` can also be blind to what bifurcation parameter (axis) is used for `ModelA`. It can receive `@lens _.alpha` or `@lens _.beta` and then just post-compose it with `@lens _.A`.

There are likely other ways to do similar things. But I find that lens from [Setfield.jl](https://github.com/jw3126/Setfield.jl) provides a very elegant way to express bifurcation parameter (or in general the “axes” along which you want to change something or compute the derivative).
