16
16
17
17
assertnonnegative (l) = (l >= 0 || throw (ArgumentError (" l must be >= 0, received " * string (l))))
18
18
19
- function checksize (arr, lmax)
20
- maximum (axes (arr,1 )) >= lmax || throw (ArgumentError (" array is not large enough to store all values" ))
21
- end
22
19
function checklength (arr, minlength)
23
20
length (arr) >= minlength || throw (ArgumentError (
24
21
" array is not large enough to store all values, require a minimum length of " * string (minlength)))
@@ -168,6 +165,39 @@ function _checkvalues(x, l, n)
168
165
n >= 0 || throw (ArgumentError (" order of derivative n must be >= 0" ))
169
166
end
170
167
168
+ Base. @propagate_inbounds function _unsafednPl! (cache, x, l, n)
169
+ # unsafe, assumes 1-based indexing
170
+ checklength (cache, l - n + 1 )
171
+ if n == l # may short-circuit this
172
+ cache[1 ] = doublefactorial (eltype (cache), 2 l- 1 )
173
+ else
174
+ collectPl! (cache, x, lmax = l - n)
175
+
176
+ for ni in 1 : n
177
+ # We denote the terms as P_ni_li
178
+
179
+ # li == ni
180
+ P_nim1_nim1 = cache[1 ]
181
+ P_ni_ni = dPl_recursion (eltype (cache), ni, ni, nothing , P_nim1_nim1, nothing , x)
182
+ cache[1 ] = P_ni_ni
183
+
184
+ # li == ni + 1
185
+ P_nim1_ni = cache[2 ]
186
+ P_ni_nip1 = dPl_recursion (eltype (cache), ni + 1 , ni, P_ni_ni, P_nim1_ni, nothing , x)
187
+ cache[2 ] = P_ni_nip1
188
+
189
+ for li in ni+ 2 : min (l, l - n + ni)
190
+ P_ni_lim2 = cache[li - ni - 1 ]
191
+ P_ni_lim1 = cache[li - ni]
192
+ P_nim1_lim1 = cache[li - ni + 1 ]
193
+ P_ni_li = dPl_recursion (eltype (cache), li, ni, P_ni_lim1, P_nim1_lim1, P_ni_lim2, x)
194
+ cache[li - ni + 1 ] = P_ni_li
195
+ end
196
+ end
197
+ end
198
+ nothing
199
+ end
200
+
171
201
"""
172
202
dnPl(x, l::Integer, n::Integer, [cache::AbstractVector])
173
203
@@ -188,7 +218,7 @@ julia> dnPl(0.5, 4, 0) == Pl(0.5, 4) # zero-th order derivative == Pl(x)
188
218
true
189
219
```
190
220
"""
191
- function dnPl (x, l:: Integer , n:: Integer ,
221
+ Base . @propagate_inbounds function dnPl (x, l:: Integer , n:: Integer ,
192
222
A = begin
193
223
_checkvalues (x, l, n)
194
224
# do not allocate A if the value is trivially zero
@@ -200,42 +230,14 @@ function dnPl(x, l::Integer, n::Integer,
200
230
)
201
231
202
232
_checkvalues (x, l, n)
203
- checklength (A, l - n + 1 )
204
-
205
- cache = OffsetArrays. no_offset_view (A)
206
-
207
233
# check if the value is trivially zero in case A is provided in the function call
208
234
if l < n
209
- return zero (eltype (cache ))
235
+ return zero (eltype (A ))
210
236
end
211
-
212
- if n == l # may short-circuit this
213
- cache[1 ] = doublefactorial (eltype (cache), 2 l- 1 )
214
- else
215
- collectPl! (cache, x, lmax = l - n)
216
-
217
- for ni in 1 : n
218
- # We denote the terms as P_ni_li
219
-
220
- # li == ni
221
- P_nim1_nim1 = cache[1 ]
222
- P_ni_ni = dPl_recursion (eltype (cache), ni, ni, nothing , P_nim1_nim1, nothing , x)
223
- cache[1 ] = P_ni_ni
224
237
225
- # li == ni + 1
226
- P_nim1_ni = cache[2 ]
227
- P_ni_nip1 = dPl_recursion (eltype (cache), ni + 1 , ni, P_ni_ni, P_nim1_ni, nothing , x)
228
- cache[2 ] = P_ni_nip1
229
-
230
- for li in ni+ 2 : min (l, l - n + ni)
231
- P_ni_lim2 = cache[li - ni - 1 ]
232
- P_ni_lim1 = cache[li - ni]
233
- P_nim1_lim1 = cache[li - ni + 1 ]
234
- P_ni_li = dPl_recursion (eltype (cache), li, ni, P_ni_lim1, P_nim1_lim1, P_ni_lim2, x)
235
- cache[li - ni + 1 ] = P_ni_li
236
- end
237
- end
238
- end
238
+ cache = OffsetArrays. no_offset_view (A)
239
+ # function barrier, as no_offset_view may be type-unstable
240
+ _unsafednPl! (cache, x, l, n)
239
241
240
242
return cache[l - n + 1 ]
241
243
end
@@ -271,13 +273,12 @@ julia> collectPl!(v, 0.5, lmax = 3) # only l from 0 to 3 are populated
271
273
```
272
274
"""
273
275
function collectPl! (v:: AbstractVector , x; lmax:: Integer = length (v) - 1 )
274
- v_0based = OffsetArray (v, OffsetArrays. Origin (0 ))
275
- checksize (v_0based, lmax)
276
+ checklength (v, lmax + 1 )
276
277
277
278
iter = LegendrePolynomialIterator (x, lmax)
278
279
279
280
for (l, Pl) in pairs (iter)
280
- v_0based[l ] = Pl
281
+ v[l + firstindex (v) ] = Pl
281
282
end
282
283
283
284
v
@@ -363,7 +364,7 @@ function collectdnPl!(v, x; lmax::Integer, n::Integer)
363
364
# trivially zero for l < n
364
365
fill! ((@view v[(0 : n- 1 ) .+ firstindex (v)]), zero (eltype (v)))
365
366
# populate the other elements
366
- dnPl (x, lmax, n, @view v[(n: lmax) .+ firstindex (v)])
367
+ @inbounds dnPl (x, lmax, n, @view v[(n: lmax) .+ firstindex (v)])
367
368
368
369
v
369
370
end
0 commit comments