@@ -294,14 +294,17 @@ function finite_difference_jacobian(
294294 copyto! (x1, x)
295295 end
296296
297- if ! (f_in isa Nothing)
298- vecfx = _vec (f_in)
297+ # Single assignment site: `vecfx` is captured by the `calculate_Ji_*` closures
298+ # below, and a captured variable with several assignment sites is boxed, which
299+ # makes the whole function's return type uninferrable.
300+ vecfx = if ! (f_in isa Nothing)
301+ _vec (f_in)
299302 elseif fdtype == Val (:forward )
300- vecfx = _vec (f (x))
303+ _vec (f (x))
301304 elseif fdtype == Val (:complex ) && returntype <: Real
302- vecfx = real (fx)
305+ real (fx)
303306 else
304- vecfx = _vec (fx)
307+ _vec (fx)
305308 end
306309 vecx = _vec (x)
307310 J = jac_prototype isa Nothing ?
@@ -310,13 +313,16 @@ function finite_difference_jacobian(
310313 nrows, ncols = size (J)
311314
312315 if ! (sparsity isa Nothing)
313- rows_index, cols_index = ArrayInterface. findstructralnz (sparsity)
314- rows_index = [rows_index [i] for i in 1 : length (rows_index )]
315- cols_index = [cols_index [i] for i in 1 : length (cols_index )]
316+ structural_rows, structural_cols = ArrayInterface. findstructralnz (sparsity)
317+ rows_index = [structural_rows [i] for i in 1 : length (structural_rows )]
318+ cols_index = [structural_cols [i] for i in 1 : length (structural_cols )]
316319 end
317320
318321 if fdtype == Val (:forward )
322+ # `local` keeps these from aliasing (and thereby boxing) the same-named
323+ # variables of the enclosing function; see the `vecfx` comment above.
319324 function calculate_Ji_forward (i)
325+ local x_save, epsilon, _vecx1, _x1, vecfx1, dx
320326 x_save = ArrayInterface. allowed_getindex (vecx, i)
321327 epsilon = compute_epsilon (Val (:forward ), x_save, relstep, absstep, dir)
322328 _vecx1 = setindex (vecx, x_save+ epsilon, i)
@@ -336,12 +342,12 @@ function finite_difference_jacobian(
336342 J = J + _make_Ji (J, eltype (x), dx, color_i, nrows, ncols)
337343 else
338344 tmp = norm (vecx .* (colorvec .== color_i))
339- epsilon = compute_epsilon (
345+ epsilon_c = compute_epsilon (
340346 Val (:forward ), sqrt (tmp), relstep, absstep, dir)
341- _vecx = @. vecx + epsilon * (colorvec == color_i)
347+ _vecx = @. vecx + epsilon_c * (colorvec == color_i)
342348 _x = reshape (_vecx, axes (x))
343349 vecfx1 = _vec (f (_x))
344- dx = (vecfx1- vecfx)/ epsilon
350+ dx = (vecfx1- vecfx)/ epsilon_c
345351 Ji = _make_Ji (
346352 J, rows_index, cols_index, dx, colorvec, color_i, nrows, ncols)
347353 J = J + Ji
@@ -354,15 +360,16 @@ function finite_difference_jacobian(
354360 # unsafe — the cache may have been built via `similar(x)` or reused at a
355361 # different x — so we always perturb around `vecx` directly.
356362 function calculate_Ji_central (i)
363+ local x_save, epsilon, _vecx1, _vecx, _x1, _x, vecfx1, vecfx0, dx
357364 x_save = ArrayInterface. allowed_getindex (vecx, i)
358365 epsilon = compute_epsilon (Val (:forward ), x_save, relstep, absstep, dir)
359366 _vecx1 = setindex (vecx, x_save+ epsilon, i)
360367 _vecx = setindex (vecx, x_save- epsilon, i)
361368 _x1 = reshape (_vecx1, axes (x))
362369 _x = reshape (_vecx, axes (x))
363370 vecfx1 = _vec (f (_x1))
364- vecfx = _vec (f (_x))
365- dx = (vecfx1- vecfx )/ (2 epsilon)
371+ vecfx0 = _vec (f (_x))
372+ dx = (vecfx1- vecfx0 )/ (2 epsilon)
366373 return dx
367374 end
368375
@@ -376,15 +383,15 @@ function finite_difference_jacobian(
376383 J = J + _make_Ji (J, eltype (x), dx, color_i, nrows, ncols)
377384 else
378385 tmp = norm (vecx .* (colorvec .== color_i))
379- epsilon = compute_epsilon (
386+ epsilon_c = compute_epsilon (
380387 Val (:forward ), sqrt (tmp), relstep, absstep, dir)
381- _vecx1 = @. vecx + epsilon * (colorvec == color_i)
382- _vecx = @. vecx - epsilon * (colorvec == color_i)
388+ _vecx1 = @. vecx + epsilon_c * (colorvec == color_i)
389+ _vecx = @. vecx - epsilon_c * (colorvec == color_i)
383390 _x1 = reshape (_vecx1, axes (x))
384391 _x = reshape (_vecx, axes (x))
385392 vecfx1 = _vec (f (_x1))
386- vecfx = _vec (f (_x))
387- dx = (vecfx1- vecfx )/ (2 epsilon )
393+ vecfx0 = _vec (f (_x))
394+ dx = (vecfx1- vecfx0 )/ (2 epsilon_c )
388395 Ji = _make_Ji (
389396 J, rows_index, cols_index, dx, colorvec, color_i, nrows, ncols)
390397 J = J + Ji
@@ -395,11 +402,12 @@ function finite_difference_jacobian(
395402 epsilon = eps (eltype (x))
396403
397404 function calculate_Ji_complex (i)
405+ local x_save, _vecx, _x, vecfx_c, dx
398406 x_save = ArrayInterface. allowed_getindex (vecx, i)
399407 _vecx = setindex (complex .(vecx), x_save+ im* epsilon, i)
400408 _x = reshape (_vecx, axes (x))
401- vecfx = _vec (f (_x))
402- dx = imag (vecfx )/ epsilon
409+ vecfx_c = _vec (f (_x))
410+ dx = imag (vecfx_c )/ epsilon
403411 return dx
404412 end
405413
@@ -414,8 +422,8 @@ function finite_difference_jacobian(
414422 else
415423 _vecx = @. vecx + im * epsilon * (colorvec == color_i)
416424 _x = reshape (_vecx, axes (x))
417- vecfx = _vec (f (_x))
418- dx = imag (vecfx )/ epsilon
425+ vecfx_c = _vec (f (_x))
426+ dx = imag (vecfx_c )/ epsilon
419427 Ji = _make_Ji (
420428 J, rows_index, cols_index, dx, colorvec, color_i, nrows, ncols)
421429 J = J + Ji
0 commit comments