# Automatic differentiation of \`cispi\`

**URL:** https://discourse.julialang.org/t/automatic-differentiation-of-cispi/66075
**Category:** Optimization (Mathematical)
**Tags:** zygote, chainrulescore
**Created:** [August 9, 2021, 2:01pm UTC](https://discourse.julialang.org/t/automatic-differentiation-of-cispi/66075 "2021-08-09T14:01:42Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)
#### Post date: [August 9, 2021, 2:01pm UTC](https://discourse.julialang.org/t/automatic-differentiation-of-cispi/66075/1 "2021-08-09T14:01:42Z")

</div>

I think the `rrule` for `cispi` seems to be missing. Maybe it should be included in the basic set of rules?

```julia
function loss2(data)
    sum(abs.(cispi.(data)))
end
data = ones(2,2)
loss2(data)
gradient(loss2, data)

```

yields:

```julia
julia> gradient(loss2, data)
ERROR: Non-differentiable function Core.Intrinsics.copysign_float
Stacktrace:
  [1] error(s::String)
    @ Base .\error.jl:33
  [2] macro expansion
    @ ~\.julia\packages\Zygote\TaBlo\src\compiler\interface2.jl:0 [inlined]
  [3] (::typeof(∂(λ)))(Δ::Float64)
    @ Zygote ~\.julia\packages\Zygote\TaBlo\src\compiler\interface2.jl:43
  [4] Pullback
    @ .\floatfuncs.jl:5 [inlined]
  [5] (::typeof(∂(copysign)))(Δ::Float64)
    @ Zygote ~\.julia\packages\Zygote\TaBlo\src\compiler\interface2.jl:0
  [6] Pullback
    @ .\special\trig.jl:885 [inlined]
  [7] (::typeof(∂(sincospi)))(Δ::Tuple{Float64, Float64})
    @ Zygote ~\.julia\packages\Zygote\TaBlo\src\compiler\interface2.jl:0
  [8] Pullback
    @ .\complex.jl:544 [inlined]
  [9] #1124
    @ ~\.julia\packages\Zygote\TaBlo\src\lib\broadcast.jl:192 [inlined]
 [10] #4
    @ .\generator.jl:36 [inlined]
 [11] iterate
    @ .\generator.jl:47 [inlined]
 [12] collect(itr::Base.Generator{Base.Iterators.Zip{Tuple{Matrix{Tuple{ComplexF64, typeof(∂(cispi))}}, Matrix{ComplexF64}}}, Base.var"#4#5"{Zygote.var"#1124#1130"}})
    @ Base .\array.jl:678
 [13] map
    @ .\abstractarray.jl:2383 [inlined]
 [14] (::Zygote.var"#∇broadcasted#1129"{Tuple{Matrix{Float64}}, Matrix{Tuple{ComplexF64, typeof(∂(cispi))}}, Val{2}})(ȳ::Matrix{ComplexF64})
    @ Zygote ~\.julia\packages\Zygote\TaBlo\src\lib\broadcast.jl:192
 [15] #4008#back
    @ ~\.julia\packages\ZygoteRules\OjfTt\src\adjoint.jl:59 [inlined]
 [16] #209
    @ ~\.julia\packages\Zygote\TaBlo\src\lib\lib.jl:203 [inlined]
 [17] #1746#back
    @ ~\.julia\packages\ZygoteRules\OjfTt\src\adjoint.jl:59 [inlined]
 [18] Pullback
    @ .\broadcast.jl:1309 [inlined]
 [19] (::typeof(∂(broadcasted)))(Δ::Matrix{ComplexF64})
    @ Zygote ~\.julia\packages\Zygote\TaBlo\src\compiler\interface2.jl:0
 [20] Pullback
    @ .\REPL[52]:2 [inlined]
 [21] (::typeof(∂(loss2)))(Δ::Float64)
    @ Zygote ~\.julia\packages\Zygote\TaBlo\src\compiler\interface2.jl:0
 [22] (::Zygote.var"#46#47"{typeof(∂(loss2))})(Δ::Float64)
    @ Zygote ~\.julia\packages\Zygote\TaBlo\src\compiler\interface.jl:41
 [23] gradient(f::Function, args::Matrix{Float64})
    @ Zygote ~\.julia\packages\Zygote\TaBlo\src\compiler\interface.jl:76
 [24] top-level scope
    @ REPL[54]:1

```

---

<div class="post-metadata">

### Author: ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)
#### Post date: [August 9, 2021, 2:11pm UTC](https://discourse.julialang.org/t/automatic-differentiation-of-cispi/66075/2 "2021-08-09T14:11:51Z")

</div>

A suggestion could be:

```julia
using ChainRulesCore
function ChainRulesCore.rrule(::typeof(cispi), dat)
    Y = cispi(dat)
    function cispi_pullback(outer_grad)
        return (NoTangent(), outer_grad .* conj.(1im .* pi .* Y))
    end 
    return Y, cispi_pullback
end

```

but I am not sure, if this is fully efficient wrt. broadcasting, if applied to large arrays pointwise.

---

<div class="post-metadata">

### Author: ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)
#### Post date: [August 9, 2021, 10:16pm UTC](https://discourse.julialang.org/t/automatic-differentiation-of-cispi/66075/3 "2021-08-09T22:16:24Z")

</div>

Indeed there is no rule. I think in ChainRules this wants to be `@scalar_rule`, would be good to have.

It does seem to work with ForwardDiff, which Zygote presently uses for (most) real but not complex-valued broadcasting:

```julia
julia> Zygote.gradient(x -> sum((real∘cispi).(x)), [0 0.5; 1 1.5])
([-0.0 -3.141592653589793; -0.0 3.141592653589793],)

julia> ForwardDiff.gradient(x -> sum(real.(cispi.(x))), [0 0.5 1 1.5])
1×4 Matrix{Float64}:
 0.0 -3.14159 0.0 3.14159

```

---

<div class="post-metadata">

### Author: ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)
#### Post date: [August 11, 2021, 3:27pm UTC](https://discourse.julialang.org/t/automatic-differentiation-of-cispi/66075/4 "2021-08-11T15:27:22Z")

</div>

It could be traced back to the missing `sincospi` rule, which I added (with Felix’s help) to the `ChainRules.jl` code. See this [pull request](https://github.com/JuliaDiff/ChainRules.jl/pull/497).

---

<div class="post-metadata">

### Author: ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)
#### Post date: [August 11, 2021, 3:43pm UTC](https://discourse.julialang.org/t/automatic-differentiation-of-cispi/66075/5 "2021-08-11T15:43:20Z")

</div>

Would also be good to open an issue about a rule for `copysign` since that also shouldn’t be failing here.
