ZeroTangent definition

Hi,
I am using chainrulecore for gradient calculation and rrule. I am trying to follow tutorial 18 of gridap. I cant understand the ZeroTangent in the code why we are using that and what it is suppose to do. I’ve read some thing on documentations but it is not clear to me.
thank you

using ChainRulesCore, Zygote
import ChainRulesCore: rrule
NO_FIELDS = ZeroTangent()
function gf_pf(pf_vec; β, η, phys_params, fem_params)
    pfh = FEFunction(fem_params.Pf, pf_vec)
    pth = (pf -> Threshold(pf; β, η)) ∘ pfh
    A_mat = MatrixA(pth; phys_params, fem_params)
    b_vec = assemble_vector(v->(∫(v)fem_params.dΓ_s), fem_params.V)
    u_vec = A_mat \ b_vec

    O_mat = MatrixOf(fem_params)
    real(u_vec' * O_mat * u_vec)
end

function rrule(::typeof(gf_pf), pf_vec; β, η, phys_params, fem_params)
    function U_pullback(dgdg)
      NO_FIELDS, dgdg * Dgfdpf(pf_vec; β, η, phys_params, fem_params)
    end
    gf_pf(pf_vec; β, η, phys_params, fem_params), U_pullback
end

One thing that somewhat helped my understanding of ChainRulesCore.jl is testing my code using ChainRulesTestUtils.jl:

https://juliadiff.org/ChainRulesTestUtils.jl/stable/

1 Like

At first glance it seems this one should actually be NoTangent(), but the NO_FIELDS renaming is a good clue. The pullback takes an output perturbation and “pulls it back” into an input perturbation. But the input includes the function gf_pf itself: it might be that this function has internal fields involved in differentiation (for instance if it is a closure or a callable struct). Here, the first element returned by U_pullback tells us that the derivative of the function output with respect to the function object itself is zero (or undefined with NoTangent).

1 Like