# ChainRulesCore.rrule that just calls another rrule

**URL:** <https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278>\
**Category:** General Usage\
**Tags:** autodiff\
**Created:** [September 26, 2023, 6:41pm UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278 "2023-09-26T18:41:11Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![moble](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/moble/32/23535_2.png) [@moble](https://discourse.julialang.org/u/moble)\
**Post date:** [September 26, 2023, 6:41pm UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/1 "2023-09-26T18:41:11Z")

</div>

I have defined a type `Rotor{T}` representing a _unit_ quaternion. It’s possible to construct a `Rotor{T}` in terms of its components — which avoids the (very slightly) expensive step of normalization. There’s also a function `rotor` with various methods that construct a `Rotor{T}`, while ensuring that it is normalized. Finally, due to complicated type-trickery I have to play to get rotors to play nicely with other types, I also have `Rotor` (without the `{T}`), which is basically a thin wrapper around `rotor`.

The derivatives seem to do what I expect with both `Rotor{T}` and `rotor`, but now it seems that I have to explicitly define `rrule`s for `Rotor` so that `ChainRules` doesn’t think it should be treated the same as `Rotor{T}`. I thought I’d be able to do something like

```julia
ChainRulesCore.rrule(::Type{Rotor}, w, x, y, z) = ChainRulesCore.rrule(rotor, w, x, y, z)

```

but when I try

```julia
f(a,b,c,d) = abs2(Rotor(a,b,c,d))
Zygote.gradient(f, 1.2, 3.4, 5.6, 7.8)

```

I get an error:

* * *

```julia
  MethodError: no method matching iterate(::Nothing)
  
  Closest candidates are:
    iterate(::Union{LinRange, StepRangeLen})
     @ Base range.jl:880
    iterate(::Union{LinRange, StepRangeLen}, ::Integer)
     @ Base range.jl:880
    iterate(::T) where T<:Union{Base.KeySet{<:Any, <:Dict}, Base.ValueIterator{<:Dict}}
     @ Base dict.jl:698
    ...
  
  Stacktrace:
    [1] indexed_iterate(I::Nothing, i::Int64)
      @ Base ./tuple.jl:91
    [2] chain_rrule
      @ ~/.julia/packages/Zygote/4SSHS/src/compiler/chainrules.jl:223 [inlined]
    [3] macro expansion
      @ ~/.julia/packages/Zygote/4SSHS/src/compiler/interface2.jl:101 [inlined]
    [4] _pullback(::Zygote.Context{false}, ::Type{Rotor}, ::Float64, ::Float64, ::Float64, ::Float64)
      @ Zygote ~/.julia/packages/Zygote/4SSHS/src/compiler/interface2.jl:101
    [5] _pullback
      @ ~/test_rotor_ad.jl:76 [inlined]
    [6] _pullback(::Zygote.Context{false}, ::var"#10#21", ::Float64, ::Float64, ::Float64, ::Float64)
      @ Zygote ~/.julia/packages/Zygote/4SSHS/src/compiler/interface2.jl:0
    [7] pullback(::Function, ::Zygote.Context{false}, ::Float64, ::Vararg{Float64})
      @ Zygote ~/.julia/packages/Zygote/4SSHS/src/compiler/interface.jl:44
    [8] pullback(::Function, ::Float64, ::Float64, ::Vararg{Float64})
      @ Zygote ~/.julia/packages/Zygote/4SSHS/src/compiler/interface.jl:42
    [9] gradient(::Function, ::Float64, ::Vararg{Float64})
      @ Zygote ~/.julia/packages/Zygote/4SSHS/src/compiler/interface.jl:96
   [10] macro expansion
      @ ~/test_rotor_ad.jl:79 [inlined]

```

Am I making a silly mistake? Or going about this all wrong?

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [September 26, 2023, 7:15pm UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/2 "2023-09-26T19:15:41Z")

</div>

I think this may have something to do with [`RuleConfig`](https://juliadiff.org/ChainRulesCore.jl/stable/rule_author/superpowers/ruleconfig.html#Writing-rules-that-call-back-into-AD) and calling back into AD, so maybe adding a `ruleconfig` argument somewhere would help. But I’m not 100% sure.

---

<div class="post-metadata">

**Author:** ![moble](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/moble/32/23535_2.png) [@moble](https://discourse.julialang.org/u/moble)\
**Post date:** [September 26, 2023, 7:46pm UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/3 "2023-09-26T19:46:51Z")

</div>

Ah, yes! This seems to work perfectly:

```julia
rrule(config::RuleConfig, ::Type{Rotor}, args...) = rrule_via_ad(config, rotor, args...)

```

(And the `RuleConfig` seems to break some ambiguities that prevented me from slurping before, so it’s even easier.) Thanks very much!

---

<div class="post-metadata">

**Author:** ![moble](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/moble/32/23535_2.png) [@moble](https://discourse.julialang.org/u/moble)\
**Post date:** [September 28, 2023, 7:29pm UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/4 "2023-09-28T19:29:24Z")

</div>

Hmm… Except that if I use this, `test_rrule(Rotor, w, x, y, z)` fails when checking inferred types, complaining that

```julia
test_rrule: Rotor on Float64,Float64,Float64,Float64: Error During Test at ~/.julia/packages/ChainRulesTestUtils/C9L2i/src/testers.jl:202
  Got exception outside of a @test
  return type Tuple{NoTangent, Vararg{Float64, 4}} does not match inferred return type Tuple

```

It fails even if I explicitly insert the arguments instead of slurping with `args...`. I wonder if this will cause slowdowns.

For now I’m just passing `check_inferred=false` to skip that check, but I welcome any suggestions.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [September 29, 2023, 7:06am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/5 "2023-09-29T07:06:40Z")

</div>

I’ve encountered that before, the trouble with `rrule_via_ad` is that it uses the AD backend to derive the pullback, so if the backend is unstable you get what’s coming for you. But in this case the backend is FiniteDifferences in ChainRulesTestUtils so that shouldn’t happen?  
Ideally I’d like to call another `rrule` directly without resorting to `rrule_via_ad` but I don’t know how to do that. And when I don’t know, I ruthlessly tag @oxinabox

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [September 29, 2023, 7:24am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/6 "2023-09-29T07:24:33Z")

</div>

> [@moble](#):
>
> For now I’m just passing `check_inferred=false` to skip that check, but I welcome any suggestions.

A lot of things break inference. so that’s not the worst. A lot of rrules have that check disabled.  
and that check doesn’t test it in an ideal scenario since it isn’t put somewhere it can inline.  
So often things are not so bad as they.

You will have to look into why inference is failing e.g. using Cthulhu.jl

* * *

If you are sure you will have an `rrule` you can directly call one `rrule` from another.  
The `no method matching iterate(::Nothing)` suggest that you do not have the rrule for the function `rotor`.  
So you need `rrule_via_ad` so it can determine it via the AD system.

* * *

The test config in ChainRulesTestUtils first tries to just directly use the `rrule` and then if it doesn’t find one it falls back to finite differences

> <https://github.com/JuliaDiff/ChainRulesTestUtils.jl/blob/c421f7c3b37dcca8fc7bcb316ba9f11c94293352/src/rule_config.jl>

If you want to disable that fallback you could write a new rule config

```julia
struct RuleOnlyConfig <: RuleConfig{Union{HasReverseMode, HasForwardsMode}} end
function ChainRulesCore.frule_via_ad(config::RuleOnlyConfig, ȧrgs, f, args...; kws...)

    # try using a rule
    ret = frule(config, ȧrgs, f, args...; kws...)
    if isnothing(ret)
        error("rule found")
    else
        return ret
    end
end

function ChainRulesCore.rrule_via_ad(config::RuleOnlyConfig, f, args...; kws...)
    ret = rrule(config, f, args...; kws...)
    if isnothing(ret)
        error("rule found")
    else
        return ret
    end
end

```

then pass that to `test_rrule` vis the `rule_config` kwarg

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [September 29, 2023, 8:02am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/7 "2023-09-29T08:02:17Z")

</div>

> [@oxinabox](#):
>
> The `no method matching iterate(::Nothing)` suggest that you do not have the rrule for the function `rotor`.

That is a frequent error, do you think it deserves a mention in the docs? Sometimes it’s hard to catch because the operations on `nothing` go on for a while until they break later.

> [@oxinabox](#):
>
> If you are sure you will have an `rrule` you can directly call one `rrule` from another.

It’s weird cause there was an `rrule` indeed, or at least OP thought so.  
I assume that the `nothing` error happens because there is a

```julia
function rrule(args...; kwargs...) end

```

defined [somewhere](https://github.com/JuliaDiff/ChainRulesCore.jl/blob/02d455ef94509310e5c29ce4b5085ab689f3d03b/src/rules.jl#L131). Would it make sense to get rid of it so that we can have a proper informative `MethodError` in these situations?

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [September 29, 2023, 8:09am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/8 "2023-09-29T08:09:14Z")

</div>

It is an intentional feature of ChainRulesCore that it returns `nothing` when there is no rule.  
It’s from before I was involed in the project and is from when julia was a different language (like 0.4 days? When ChainRules was part of the plans for Capstan.jl).  
We should consider getting rid of it was part of ChainRules 2.0  
feel encourages to open an issue to revisit that decision and we will will put the 2.0 milestone on it.

> That is a frequent error, do you think it deserves a mention in the docs?

Yes, we can at least add it to the FAQ.  
Please open a PR

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [September 29, 2023, 8:11am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/9 "2023-09-29T08:11:32Z")

</div>

> <https://github.com/JuliaDiff/ChainRulesCore.jl/issues/632>
>
> This frequent error happens because of the default dispatches
> 
> \`\`\`julia
> frule…(ȧrgs, f, ::Vararg{Any}) = nothing
> rrule(::Any, ::Vararg{Any}) = nothing
> \`\`\`
> 
> so when no \`rrule\` is defined, \`nothing\` is returned.
> Unfortunately, it is hard to catch because the computations with \`nothing\` can go on for a while before erroring.
> 
> I wonder if removing these default dispatches would break something badly?

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [September 29, 2023, 8:21am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/10 "2023-09-29T08:21:15Z")

</div>

> <https://github.com/JuliaDiff/ChainRulesCore.jl/pull/633>
>
> Add a section to the FAQ on the error
> 
> \`\`\`julia
> MethodError: no method matching …iterate(::Nothing)
> \`\`\`
> 
> Partial fix for #632 until a breaking 2.0 release can get rid of the default dispatch

---

<div class="post-metadata">

**Author:** ![trahflow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/trahflow/32/30585_2.png) [@trahflow](https://discourse.julialang.org/u/trahflow)\
**Post date:** [September 29, 2023, 9:43am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/11 "2023-09-29T09:43:49Z")

</div>

Hi @moble ,

am I right that you were, like me, looking at [Rotations.jl](https://github.com/JuliaGeometry/Rotations.jl), found unit quaternions for rotations implemented, but were missing AD support?  
I also ended up doing my own basic implementation (for the additional reason that I wanted GPU/CUDA support).  
There exists an issue though for [adding ChainRulesCore support to it](https://github.com/JuliaGeometry/Rotations.jl/issues/129), mentioning that PRs would be welcome.  
Would you be interested in tackling this together?

---

<div class="post-metadata">

**Author:** ![moble](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/moble/32/23535_2.png) [@moble](https://discourse.julialang.org/u/moble)\
**Post date:** [October 4, 2023, 3:48am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/12 "2023-10-04T03:48:19Z")

</div>

> [@oxinabox](#):
>
> If you are sure you will have an `rrule` you can directly call one `rrule` from another.  
> The `no method matching iterate(::Nothing)` suggest that you do not have the rrule for the function `rotor`.

Upon closer inspection, I hadn’t covered the right combination of types. Once I fixed that, it worked. Thanks!

---

<div class="post-metadata">

**Author:** ![moble](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/moble/32/23535_2.png) [@moble](https://discourse.julialang.org/u/moble)\
**Post date:** [October 4, 2023, 4:07am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/13 "2023-10-04T04:07:27Z")

</div>

> [@trahflow](#):
>
> am I right that you were, like me, looking at [Rotations.jl](https://github.com/JuliaGeometry/Rotations.jl), found unit quaternions for rotations implemented, but were missing AD support?

No, I hadn’t actually seen Rotations.jl when I started my package. But more than that, I do need non-unit quaternions for a lot of things also, so it doesn’t look like it’s quite right for me. Even Quaternions.jl — which Rotations.jl appears to base its `QuatRotation` on — didn’t really fit what I was going for. At this point, my package has grown to be quite large, and fits my needs well, so I don’t think I’ll be contributing to Rotations.jl.

But certainly feel free to use anything I’ve developed (currently working in my [chainrules branch](https://github.com/moble/Quaternionic.jl/tree/chainrules)).

---

<div class="post-metadata">

**Author:** ![trahflow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/trahflow/32/30585_2.png) [@trahflow](https://discourse.julialang.org/u/trahflow)\
**Post date:** [October 5, 2023, 11:18am UTC](https://discourse.julialang.org/t/chainrulescore-rrule-that-just-calls-another-rrule/104278/14 "2023-10-05T11:18:25Z")

</div>

Thanks for the heads up!  
I’ll give it a shot at some point
