# Zygote: ERROR: LoadError: type NamedTuple has no field first

Hi,
I’m trying to get started using Zygote in a numerical simulation. Basically I need to differentiate through a Laplace solver and am getting an error which I don’t know how to handle.

Here is the code:

``````using Plots
using Statistics
using LinearAlgebra
using Zygote

function invert_laplace(ρ,  Nz, Lz)
# Solve Laplace equation
# ρ: RHS function
# Nz: Number of grid points
# Lz: Length of the domain
Δz = Lz / Nz
zrg = range(0.0, step=Δz, length=Nz)
# Squeeze a minus in here.
invΔz² = -1.0 / Δz / Δz

# Periodic boundary conditions. First row of A is just [1, 0, ... 0]
A = diagm(0 => -2.0 * invΔz² * vcat([-0.5 / invΔz²], ones(Nz-1)),
1 => invΔz² * vcat([0.0], ones(Nz - 2)),
-1 => invΔz² * ones(Nz-1), -Nz+1 => [invΔz²])
# Fix phi(x=0) = 0.
ρvec = vcat([0.0], ρ(zrg[2:end]))
ϕ_num = A \ ρvec
return(ϕ_num)
end

function my_laplace_test(a)
# Use a RHS that scales linear with and
# solving ∂ₓ² ϕ = -a ρ is linear in a
# maximum(ϕ_num) should be a.
Nz = 256
Lz = 1.0
ρ = z -> a * 4. * π * π * sin.(2π * z)
ϕ_num = invert_laplace(ρ, Nz, Lz)
return maximum(ϕ_num)
end

# Now let's try to differentiate through the solver:
``````

But this gives me an error:

ERROR: LoadError: type NamedTuple has no field first

Stacktrace:

 getproperty(::NamedTuple{(:second,),Tuple{Array{Float64,1}}}, ::Symbol) at ./Base.jl:33
 macro expansion at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/lib/lib.jl:287 [inlined]
 (::Zygote.Jnew{Pair{Int64,Array{Float64,1}},Nothing,false})(::NamedTuple{(:second,),Tuple{Array{Float64,1}}}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/lib/lib.jl:279
 Pair at ./pair.jl:12 [inlined]
 Pair at ./pair.jl:15 [inlined]
 (::typeof(∂(Pair)))(::NamedTuple{(:second,),Tuple{Array{Float64,1}}}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface2.jl:0
 invert_laplace at /Users/ralph/source/julia/zygote_tests/test_laplace_direct.jl:25 [inlined]
 (::typeof(∂(invert_laplace)))(::Array{Float64,1}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface2.jl:0
 my_laplace_test at /Users/ralph/source/julia/zygote_tests/test_laplace_direct.jl:67 [inlined]
 (::Zygote.var"#41#42"{typeof(∂(my_laplace_test))})(::Float64) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface.jl:40
 top-level scope at /Users/ralph/source/julia/zygote_tests/test_laplace_direct.jl:72
 include(::Function, ::Module, ::String) at ./Base.jl:380
 include(::Module, ::String) at ./Base.jl:368
 exec_options(::Base.JLOptions) at ./client.jl:296
 _start() at ./client.jl:506

``````
Here  refers to the line where the matrix A is constructed. Does anyone have an idea what to do here?``````

Seems like it is hitting Add adjoint for `pairs(::NamedTuple)` and `Pair` by YingboMa · Pull Request #452 · FluxML/Zygote.jl · GitHub which should be able to handle this.

Can we try to isolate the issue a bit? My thinking is that this shows up with the call to `diagm` maybe we are missing a constructor for that.

You’re right. If I replace construction of the A matrix with

``````A = Matrix(1.0I, Nz, Nz)
``````

the code runs fine. As a quick fix I’ll probably remove all the syntax candy and construct A in a for-loop.

But should zygote in principle be able to handle this?

Constructing it like that might be slow; not sure

It should I think, pending a simple adjoint for the constructor

Here is the example that works:

``````using Statistics
using LinearAlgebra
using Zygote

# Test zygote's capability to differentiate through a laplace solver.
# This example initializes a profile
# ρ = a 4π² sin(2 π x)
# and solves the Laplace equation
# ϕ = ∇⁻²ρ on x ∈ (0:1) with periodic boundary conditions:
# ϕ(x) = ϕ(x+1)
# Since the mean of ϕ is undetermined, we also fix ϕ(0) = 0.

function invert_laplace(ρ, Nz, Lz)
# Solve Laplace equation: ϕ = ∇⁻² ρ on x ∈ (0:Lz).
# ρ: RHS function
# Nz: Number of grid points
# Lz: Length of the domain
# Returns: ϕ
Δz = Lz / Nz
# zrg = range(0.0, step=Δz, length=Nz)
zrg = 0.0:Δz:Lz-Δz
# Squeeze a minus in here.
invΔz² = -1.0 / Δz / Δz

# To fix ϕ(0) = 0 we have to get the equation
# ϕ * 1 = 0 in the linear system. To this by fixing A[1,1] = 1 and ρ = 0.

# # Periodic boundary conditions. First row of A is just [1, 0, ... 0]
# A = diagm(0 => -2.0 * invΔz² * vcat([-0.5 / invΔz²], ones(Nz-1)),
#           1 => invΔz² * vcat([0.0], ones(Nz - 2)),
#           -1 => invΔz² * ones(Nz-1), -Nz+1 => [invΔz²])
# # Fix phi(x=0) = 0.

A0 = Zygote.Buffer(zeros(Nz, Nz))
for n ∈ 1:Nz
for m ∈ 1:Nz
A0[n,m] = 0.0
end
end
for n ∈ 2:Nz
A0[n, n] = -2.0 * invΔz²
A0[n, n-1] = invΔz²
A0[n-1, n] = invΔz²
end
A0[1,1] = 1.0
A0[1, 2] = 0.0
A0[32,1] = invΔz²

A = copy(A0)
ρvec = vcat([0.0], ρ(zrg[2:end]))
ϕ_num = A \ ρvec
return(ϕ_num)
end

function my_laplace_test(a)
# Use a RHS that scales linear with and solving ∂ₓ² ϕ = -a - ρ is linear in a
# maximum(ϕ_num) should be a.
Nz = 256
Lz = 1.0
ρ = z -> a * 4. * π * π * sin.(2π * z)
ϕ_num = invert_laplace(ρ, Nz, Lz)
return maximum(ϕ_num)
end

# Now let's try to differentiate through the solver:
``````

Now there are 2 issues:
1.

``````    zrg = range(0.0, step=Δz, length=Nz)
zrg = 0.0:Δz:Lz-Δz
``````

Using the first line gives an error:

``````  % /Applications/Julia-1.5.app/Contents/Resources/julia/bin/julia -i  test_laplace2.jl                                                                                                                                                                                                                                                     !10070
Stacktrace:
 error(::String) at ./error.jl:33
 (::Zygote.Jnew{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Nothing,false})(::Array{Float64,1}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/lib/lib.jl:301
 StepRangeLen at ./range.jl:352 [inlined]
 (::typeof(∂(StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}})))(::Array{Float64,1}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface2.jl:0
 StepRangeLen at ./twiceprecision.jl:358 [inlined]
 steprangelen_hp at ./twiceprecision.jl:344 [inlined]
 (::typeof(∂(steprangelen_hp)))(::Array{Float64,1}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface2.jl:0
 _range at ./twiceprecision.jl:447 [inlined]
 (::typeof(∂(_range)))(::Array{Float64,1}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface2.jl:0
 #range#43 at ./range.jl:91 [inlined]
 (::typeof(∂(#range#43)))(::Array{Float64,1}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface2.jl:0 (repeats 2 times)
 invert_laplace at /Users/ralph/source/julia/zygote_tests/test_laplace2.jl:12 [inlined]
 (::typeof(∂(invert_laplace)))(::Array{Float64,1}) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface2.jl:0
 my_laplace_test at /Users/ralph/source/julia/zygote_tests/test_laplace2.jl:50 [inlined]
 (::typeof(∂(my_laplace_test)))(::Float64) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface2.jl:0
 (::Zygote.var"#41#42"{typeof(∂(my_laplace_test))})(::Float64) at /Users/ralph/.julia/packages/Zygote/7Jrhj/src/compiler/interface.jl:40
 top-level scope at /Users/ralph/source/julia/zygote_tests/test_laplace2.jl:55
 include(::Function, ::Module, ::String) at ./Base.jl:380
 include(::Module, ::String) at ./Base.jl:368
 exec_options(::Base.JLOptions) at ./client.jl:296
 _start() at ./client.jl:506
in expression starting at /Users/ralph/source/julia/zygote_tests/test_laplace2.jl:55
``````

Where would I need to define this custom adjoint constructor?

And 2.:
While the diagm syntax is nicer, the explicit construction is fine too. Of course it would be nice to have, but it’s not a must have. But just in case, what would need to be done to get custom adjoint constructors for diagm started?

It would be good to get a PR to Zygote or ChainRules with the adjoints for the specific constructors. Ditto for the first case. note that

``````julia> Flux.gradient(x -> sum(1:0.5:x), 5)
(nothing,)
``````

does work fine.

You could also wrap it into a `Zygote.ignore` block