StatProfilerHTML.jl report
Generated on Thu, 21 Dec 2023 12:59:22
File source code
Line Exclusive Inclusive Code
1 struct Partials{N,V} <: AbstractVector{V}
2 values::NTuple{N,V}
3 end
4
5 ##############################
6 # Utility/Accessor Functions #
7 ##############################
8
9 @generated function single_seed(::Type{Partials{N,V}}, ::Val{i}) where {N,V,i}
10 ex = Expr(:tuple, [ifelse(i === j, :(one(V)), :(zero(V))) for j in 1:N]...)
11 return :(Partials($(ex)))
12 end
13
14 @inline valtype(::Partials{N,V}) where {N,V} = V
15 @inline valtype(::Type{Partials{N,V}}) where {N,V} = V
16
17 @inline npartials(::Partials{N}) where {N} = N
18 @inline npartials(::Type{Partials{N,V}}) where {N,V} = N
19
20 @inline Base.length(::Partials{N}) where {N} = N
21 @inline Base.size(::Partials{N}) where {N} = (N,)
22
23 @inline Base.@propagate_inbounds Base.getindex(partials::Partials, i::Int) = partials.values[i]
24
25 Base.iterate(partials::Partials) = iterate(partials.values)
26 Base.iterate(partials::Partials, i) = iterate(partials.values, i)
27
28 Base.IndexStyle(::Type{<:Partials}) = IndexLinear()
29
30 # Can be deleted after https://github.com/JuliaLang/julia/pull/29854 is on a release
31 Base.mightalias(x::AbstractArray, y::Partials) = false
32
33 #####################
34 # Generic Functions #
35 #####################
36
37 @inline Base.iszero(partials::Partials) = iszero_tuple(partials.values)
38
39 @inline Base.zero(partials::Partials) = zero(typeof(partials))
40 @inline Base.zero(::Type{Partials{N,V}}) where {N,V} = Partials{N,V}(zero_tuple(NTuple{N,V}))
41
42 @inline Base.one(partials::Partials) = one(typeof(partials))
43 @inline Base.one(::Type{Partials{N,V}}) where {N,V} = Partials{N,V}(one_tuple(NTuple{N,V}))
44
45 @inline Random.rand(partials::Partials) = rand(typeof(partials))
46 @inline Random.rand(::Type{Partials{N,V}}) where {N,V} = Partials{N,V}(rand_tuple(NTuple{N,V}))
47 @inline Random.rand(rng::AbstractRNG, partials::Partials) = rand(rng, typeof(partials))
48 @inline Random.rand(rng::AbstractRNG, ::Type{Partials{N,V}}) where {N,V} = Partials{N,V}(rand_tuple(rng, NTuple{N,V}))
49
50 Base.isequal(a::Partials{N}, b::Partials{N}) where {N} = isequal(a.values, b.values)
51 Base.:(==)(a::Partials{N}, b::Partials{N}) where {N} = a.values == b.values
52
53 const PARTIALS_HASH = hash(Partials)
54
55 Base.hash(partials::Partials) = hash(partials.values, PARTIALS_HASH)
56 Base.hash(partials::Partials, hsh::UInt64) = hash(hash(partials), hsh)
57
58 @inline Base.copy(partials::Partials) = partials
59
60 Base.read(io::IO, ::Type{Partials{N,V}}) where {N,V} = Partials{N,V}(ntuple(i->read(io, V), N))
61
62 function Base.write(io::IO, partials::Partials)
63 for p in partials
64 write(io, p)
65 end
66 end
67
68 ########################
69 # Conversion/Promotion #
70 ########################
71
72 Base.promote_rule(::Type{Partials{N,A}}, ::Type{Partials{N,B}}) where {N,A,B} = Partials{N,promote_type(A, B)}
73
74 Base.convert(::Type{Partials{N,V}}, partials::Partials) where {N,V} = Partials{N,V}(partials.values)
75 Base.convert(::Type{Partials{N,V}}, partials::Partials{N,V}) where {N,V} = partials
76
77 ########################
78 # Arithmetic Functions #
79 ########################
80
81 1 (0 %)
1 (0 %) samples spent in +
1 (100 %) (incl.) when called from + line 473
1 (100 %) samples spent calling add_tuples
@inline Base.:+(a::Partials{N}, b::Partials{N}) where {N} = Partials(add_tuples(a.values, b.values))
82 9 (3 %)
9 (3 %) samples spent in -
9 (100 %) (incl.) when called from - line 483
9 (100 %) samples spent calling sub_tuples
@inline Base.:-(a::Partials{N}, b::Partials{N}) where {N} = Partials(sub_tuples(a.values, b.values))
83 @inline Base.:-(partials::Partials) = Partials(minus_tuple(partials.values))
84 3 (1 %)
3 (1 %) samples spent in *
3 (100 %) (incl.) when called from dual_definition_retval line 200
3 (100 %) samples spent calling *
@inline Base.:*(x::Real, partials::Partials) = partials*x
85
86 @inline function _div_partials(a::Partials, b::Partials, aval, bval)
87 return _mul_partials(a, b, inv(bval), -(aval / (bval*bval)))
88 end
89
90 # NaN/Inf-safe methods #
91 #----------------------#
92
93 if NANSAFE_MODE_ENABLED
94 @inline function Base.:*(partials::Partials, x::Real)
95 x = ifelse(!isfinite(x) && iszero(partials), one(x), x)
96 return Partials(scale_tuple(partials.values, x))
97 end
98
99 @inline function Base.:/(partials::Partials, x::Real)
100 x = ifelse(x == zero(x) && iszero(partials), one(x), x)
101 return Partials(div_tuple_by_scalar(partials.values, x))
102 end
103
104 @inline function _mul_partials(a::Partials{N}, b::Partials{N}, x_a, x_b) where N
105 x_a = ifelse(!isfinite(x_a) && iszero(a), one(x_a), x_a)
106 x_b = ifelse(!isfinite(x_b) && iszero(b), one(x_b), x_b)
107 return Partials(mul_tuples(a.values, b.values, x_a, x_b))
108 end
109 else
110 @inline function Base.:*(partials::Partials, x::Real)
111 3 (1 %)
3 (1 %) samples spent in *
3 (100 %) (incl.) when called from * line 84
3 (100 %) samples spent calling scale_tuple
return Partials(scale_tuple(partials.values, x))
112 end
113
114 @inline function Base.:/(partials::Partials, x::Real)
115 return Partials(div_tuple_by_scalar(partials.values, x))
116 end
117
118 @inline function _mul_partials(a::Partials{N}, b::Partials{N}, x_a, x_b) where N
119 6 (2 %)
6 (2 %) samples spent in _mul_partials
6 (100 %) (incl.) when called from dual_definition_retval line 203
6 (100 %) samples spent calling mul_tuples
return Partials(mul_tuples(a.values, b.values, x_a, x_b))
120 end
121 end
122
123 # edge cases where N == 0 #
124 #-------------------------#
125
126 @inline Base.:+(a::Partials{0,A}, b::Partials{0,B}) where {A,B} = Partials{0,promote_type(A,B)}(tuple())
127 @inline Base.:+(a::Partials{0,A}, b::Partials{N,B}) where {N,A,B} = convert(Partials{N,promote_type(A,B)}, b)
128 @inline Base.:+(a::Partials{N,A}, b::Partials{0,B}) where {N,A,B} = convert(Partials{N,promote_type(A,B)}, a)
129
130 @inline Base.:-(a::Partials{0,A}, b::Partials{0,B}) where {A,B} = Partials{0,promote_type(A,B)}(tuple())
131 @inline Base.:-(a::Partials{0,A}, b::Partials{N,B}) where {N,A,B} = -(convert(Partials{N,promote_type(A,B)}, b))
132 @inline Base.:-(a::Partials{N,A}, b::Partials{0,B}) where {N,A,B} = convert(Partials{N,promote_type(A,B)}, a)
133 @inline Base.:-(partials::Partials{0,V}) where {V} = partials
134
135 @inline Base.:*(partials::Partials{0,V}, x::Real) where {V} = Partials{0,promote_type(V,typeof(x))}(tuple())
136 @inline Base.:*(x::Real, partials::Partials{0,V}) where {V} = Partials{0,promote_type(V,typeof(x))}(tuple())
137
138 @inline Base.:/(partials::Partials{0,V}, x::Real) where {V} = Partials{0,promote_type(V,typeof(x))}(tuple())
139
140 @inline _mul_partials(a::Partials{0,A}, b::Partials{0,B}, afactor, bfactor) where {A,B} = Partials{0,promote_type(A,B)}(tuple())
141 @inline _mul_partials(a::Partials{0,A}, b::Partials{N,B}, afactor, bfactor) where {N,A,B} = bfactor * b
142 @inline _mul_partials(a::Partials{N,A}, b::Partials{0,B}, afactor, bfactor) where {N,A,B} = afactor * a
143
144 ##################################
145 # Generated Functions on NTuples #
146 ##################################
147 # The below functions are generally
148 # equivalent to directly mapping over
149 # tuples using `map`, but run a bit
150 # faster since they generate inline code
151 # that doesn't rely on closures.
152
153 function tupexpr(f, N)
154 ex = Expr(:tuple, [f(i) for i=1:N]...)
155 return quote
156 $(Expr(:meta, :inline))
157 19 (7 %)
19 (7 %) samples spent in macro expansion
9 (47 %) (incl.) when called from sub_tuples line 212
6 (32 %) (incl.) when called from mul_tuples line 220
3 (16 %) (incl.) when called from scale_tuple line 200
1 (5 %) (incl.) when called from add_tuples line 208
9 (47 %) samples spent calling -
8 (42 %) samples spent calling *
2 (11 %) samples spent calling +
@inbounds return $ex
158 end
159 end
160
161 @inline iszero_tuple(::Tuple{}) = true
162 @inline zero_tuple(::Type{Tuple{}}) = tuple()
163 @inline one_tuple(::Type{Tuple{}}) = tuple()
164 @inline rand_tuple(::AbstractRNG, ::Type{Tuple{}}) = tuple()
165 @inline rand_tuple(::Type{Tuple{}}) = tuple()
166
167 @generated function iszero_tuple(tup::NTuple{N,V}) where {N,V}
168 ex = Expr(:&&, [:(z == tup[$i]) for i=1:N]...)
169 return quote
170 z = zero(V)
171 $(Expr(:meta, :inline))
172 @inbounds return $ex
173 end
174 end
175
176 @generated function zero_tuple(::Type{NTuple{N,V}}) where {N,V}
177 ex = tupexpr(i -> :(z), N)
178 return quote
179 z = zero(V)
180 return $ex
181 end
182 end
183
184 @generated function one_tuple(::Type{NTuple{N,V}}) where {N,V}
185 ex = tupexpr(i -> :(z), N)
186 return quote
187 z = one(V)
188 return $ex
189 end
190 end
191
192 @generated function rand_tuple(rng::AbstractRNG, ::Type{NTuple{N,V}}) where {N,V}
193 return tupexpr(i -> :(rand(rng, V)), N)
194 end
195
196 @generated function rand_tuple(::Type{NTuple{N,V}}) where {N,V}
197 return tupexpr(i -> :(rand(V)), N)
198 end
199
200 3 (1 %)
3 (1 %) samples spent in scale_tuple
3 (100 %) (incl.) when called from * line 111
3 (100 %) samples spent calling macro expansion
@generated function scale_tuple(tup::NTuple{N}, x) where N
201 return tupexpr(i -> :(tup[$i] * x), N)
202 end
203
204 @generated function div_tuple_by_scalar(tup::NTuple{N}, x) where N
205 return tupexpr(i -> :(tup[$i] / x), N)
206 end
207
208 1 (0 %)
1 (0 %) samples spent in add_tuples
1 (100 %) (incl.) when called from + line 81
1 (100 %) samples spent calling macro expansion
@generated function add_tuples(a::NTuple{N}, b::NTuple{N}) where N
209 return tupexpr(i -> :(a[$i] + b[$i]), N)
210 end
211
212 9 (3 %)
9 (3 %) samples spent in sub_tuples
9 (100 %) (incl.) when called from - line 82
9 (100 %) samples spent calling macro expansion
@generated function sub_tuples(a::NTuple{N}, b::NTuple{N}) where N
213 return tupexpr(i -> :(a[$i] - b[$i]), N)
214 end
215
216 @generated function minus_tuple(tup::NTuple{N}) where N
217 return tupexpr(i -> :(-tup[$i]), N)
218 end
219
220 6 (2 %)
6 (2 %) samples spent in mul_tuples
6 (100 %) (incl.) when called from _mul_partials line 119
6 (100 %) samples spent calling macro expansion
@generated function mul_tuples(a::NTuple{N}, b::NTuple{N}, afactor, bfactor) where N
221 return tupexpr(i -> :((afactor * a[$i]) + (bfactor * b[$i])), N)
222 end
223
224 ###################
225 # Pretty Printing #
226 ###################
227
228 Base.show(io::IO, p::Partials{N}) where {N} = print(io, "Partials", p.values)