@@ -142,16 +142,42 @@ end
142
142
# dx::AbstractArray (when both are possible), or the reverse. So for now we just pass them through:
143
143
(:: ProjectTo{T} )(dx:: Tangent{<:T} ) where {T} = dx
144
144
145
+ # ####
146
+ # #### A related utility which wants to live nearby
147
+ # ####
148
+
149
+ """
150
+ is_non_differentiable(x) == is_non_differentiable(typeof(x))
151
+
152
+ Returns `true` if `x` is known from its type not to have derivatives, else `false`.
153
+
154
+ Should mostly agree with whether `ProjectTo(x)` maps to `AbstractZero`,
155
+ which is what the fallback method checks. The exception is that it will not look
156
+ inside abstractly typed containers like `x = Any[true, false]`.
157
+ """
158
+ is_non_differentiable (x) = is_non_differentiable (typeof (x))
159
+
160
+ is_non_differentiable (:: Type{<:Number} ) = false
161
+ is_non_differentiable (:: Type{<:NTuple{N,T}} ) where {N,T} = is_non_differentiable (T)
162
+ is_non_differentiable (:: Type{<:AbstractArray{T}} ) where {T} = is_non_differentiable (T)
163
+
164
+ function is_non_differentiable (:: Type{T} ) where {T} # fallback
165
+ PT = Base. _return_type (ProjectTo, Tuple{T}) # might be Union{} if unstable
166
+ return isconcretetype (PT) && PT <: ProjectTo{<:AbstractZero}
167
+ end
168
+
145
169
# ####
146
170
# #### `Base`
147
171
# ####
148
172
149
173
# Bool
150
174
ProjectTo (:: Bool ) = ProjectTo {NoTangent} () # same projector as ProjectTo(::AbstractZero) above
175
+ is_non_differentiable (:: Type{Bool} ) = true
151
176
152
177
# Other never-differentiable types
153
178
for T in (:Symbol , :Char , :AbstractString , :RoundingMode , :IndexStyle )
154
179
@eval ProjectTo (:: $T ) = ProjectTo {NoTangent} ()
180
+ @eval is_non_differentiable (:: Type{<:$T} ) = true
155
181
end
156
182
157
183
# Numbers
0 commit comments