# Mutating array workaround for reverse AD?

**URL:** https://discourse.julialang.org/t/mutating-array-workaround-for-reverse-ad/81009
**Category:** General Usage
**Tags:** question, zygote, reversediff
**Created:** [May 13, 2022, 11:45am UTC](https://discourse.julialang.org/t/mutating-array-workaround-for-reverse-ad/81009 "2022-05-13T11:45:45Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![beryl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beryl/32/209986_2.png) [@beryl](https://discourse.julialang.org/u/beryl)
#### Post date: [May 13, 2022, 11:45am UTC](https://discourse.julialang.org/t/mutating-array-workaround-for-reverse-ad/81009/1 "2022-05-13T11:45:45Z")

</div>

Hi,

I have yet another unsolved problem for reverse mode AD (or I think, this is the same problem as the one I posted previously: [LoadError: ArgumentError: Converting an instance of ReverseDiff.TrackedReal{Float64, Float64, Nothing} to Float64 is not defined. Please use `ReverseDiff.value` instead](https://discourse.julialang.org/t/loaderror-argumenterror-converting-an-instance-of-reversediff-trackedreal-float64-float64-nothing-to-float64-is-not-defined-please-use-reversediff-value-instead/80544)). Here is the (hopefully) MWE:

```julia
using LinearAlgebra
using Zygote, ReverseDiff

function f_test_1(A, x)
    """
    u = Ax + some constant row vector
    """
    u = A*x[2:end] .+ x[1]
    return u
end

function f_test_2(A, x)
    """
    alloc inside
    """
    u = Vector{Float64}(undef, length(x)-1)
    u .= A*x[2:end] .+ x[1]
    return u
end

function f_test_3!(u, A, x)
    """
    non-alloc ver
    """
    u .= A*x[2:end] .+ x[1]
end

# derivative:
J_f_1(A, x) = Zygote.jacobian(θ -> f_test_1(A, θ), x)
J_f_2(A, x) = Zygote.jacobian(θ -> f_test_2(A, θ), x)
J_f_3(u, A, x) = Zygote.jacobian(θ -> f_test_3!(u, A, θ), x)

```

J\_f\_1 works, however \_2 and \_3 don’t, for example:

```julia
A = Matrix{Float64}(LinearAlgebra.I, 5, 5)
x = ones(6)
u = Vector{Float64}(undef, 5)

J_f_1(A, x) # this works
J_f_2(A, x) # throws "Mutating arrays is not supported -- called copyto!(::Vector{Float64}, _...)"
J_f_3(u,A,x) # same as _2

```

Also, replacing Zygote with ReverseDiff produces similar error it seems, although the error trace shows different thing (ReverseDiff gives “ArgumentError: Converting an instance of ReverseDiff.TrackedReal{Float64, Float64, Nothing} to Float64 is not defined. Please use `ReverseDiff.value` instead.”, I tried using `ReverseDiff.value`, however it results in incorrect Jacobian (all 0.)).  
So, are there any workarounds for Zygote or ReverseDiff to work for mutating arrays (other than using f\_test\_1)? For example if I have more complicated functions which require assignments of values to the output array(s), like B[i,:,:] = … .  
Thanks.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [May 13, 2022, 12:06pm UTC](https://discourse.julialang.org/t/mutating-array-workaround-for-reverse-ad/81009/2 "2022-05-13T12:06:26Z")

</div>

> [@beryl](#):
>
> So, are there any workarounds for Zygote or ReverseDiff to work for mutating arrays (other than using f\_test\_1)? For example if I have more complicated functions which require assignments of values to the output array(s), like B[i,:,:] = … .

You could write your own `rrule` (= vector–Jacobian product) for the routines that need mutation.

I pretty much assume that for any sufficiently complicated calculation, with any AD software in any language, that I will have to write at least some manual derivatives (see also [section 5 of these notes](https://math.mit.edu/~stevenj/18.336/adjoint.pdf)).

---

<div class="post-metadata">

### Author: ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)
#### Post date: [May 13, 2022, 1:09pm UTC](https://discourse.julialang.org/t/mutating-array-workaround-for-reverse-ad/81009/3 "2022-05-13T13:09:56Z")

</div>

Just as a quick note, docstrings in Julia go above the function not below it, right now you are creating a string inside the function 🙂

Enzyme.jl does support in-place AD, but it’s BLAS support is nascent. I took your code and opened an issue so that we can make sure to add support for the necessary BLAS funcion [https://github.com/EnzymeAD/Enzyme.jl/issues/312](https://github.com/EnzymeAD/Enzyme.jl/issues/312)

---

<div class="post-metadata">

### Author: ![beryl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beryl/32/209986_2.png) [@beryl](https://discourse.julialang.org/u/beryl)
#### Post date: [May 18, 2022, 10:40am UTC](https://discourse.julialang.org/t/mutating-array-workaround-for-reverse-ad/81009/4 "2022-05-18T10:40:41Z")

</div>

> You could write your own `rrule` (= vector–Jacobian product) for the routines that need mutation.

Thanks, although currently I still haven’t fully figure out yet on how to write the `rrule` such that it could make reverse AD for mutating array works (my understanding of `rrule` is still lacking).

---

<div class="post-metadata">

### Author: ![beryl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beryl/32/209986_2.png) [@beryl](https://discourse.julialang.org/u/beryl)
#### Post date: [May 18, 2022, 10:43am UTC](https://discourse.julialang.org/t/mutating-array-workaround-for-reverse-ad/81009/5 "2022-05-18T10:43:44Z")

</div>

> Just as a quick note, docstrings in Julia go above the function not below it, right now you are creating a string inside the function 🙂

I see, thanks for pointing it out!

> Enzyme.jl does support in-place AD, but it’s BLAS support is nascent

Ok, I will check it out.

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [May 18, 2022, 12:00pm UTC](https://discourse.julialang.org/t/mutating-array-workaround-for-reverse-ad/81009/6 "2022-05-18T12:00:18Z")

</div>

> [@beryl](#):
>
> eplacing Zygote with ReverseDiff produces similar error it seems, although the error trace shows different thing (ReverseDiff gives “ArgumentError: Converting an instance of ReverseDiff.TrackedReal{Float64, Float64, Nothing} to Float64 is not defined. Please use `ReverseDiff.value` instead.”, I tried using `ReverseDiff.value` , however it res

For ReverseDiff, just do `identity.(x)` to the TrackedArray to get an Array{TrackedReal} and then make the buffers match that type. That will then reverse scalar-wise, in which case you want to use the compiled mode to accelerate it. Note that this looks like a PDE, and DifferentialEquations.jl automates this.
