ListGradient¶
Status: Stable
documented, exercised by the test suite and/or worked examples, with no known limitations recorded.
Description¶
ListGradient[f]
gives the numerical gradient of the sampled array f by finite differences: second-order central differences in the interior and one-sided differences at the edges, one array per axis. For a vector it returns a vector; for a rank-k array it returns {g1, ..., gk}.
ListGradient[f, h]
uses spacing h on every axis; ListGradient[f, {s1,
Notes
..., sk}\] gives one spacing per axis, each a scalar spacing or a coordinate vector for non-uniform sampling. For a vector, a coordinate list of the same length as f is used directly. Options: Method -\> "Centered" (default), "Forward", or "Backward"; DifferenceOrder -\> p (accuracy order, default 2); WindowLength -\> m (stencil size, default p+1); Axis -\> All | a | {a1, ...} to restrict to particular axes. Integer input yields exact Rationals and symbolic input a symbolic result; arbitrary-precision (MPFR) input keeps its precision. Real and complex machine arrays use the packed/NDArray buffer fast path, and ListGradient\[v\] compiles. ListGradient has the attribute Protected.Examples (12)¶
Every input below was run against the current Mathilda build and its output recorded.
Basic examples (3)¶
In[1]:= ListGradient[{1, 4, 9, 16, 25}]
Out[1]= {3, 4, 6, 8, 9}
In[2]:= ListGradient[{a, b, c, d, e}]
Out[2]= {-a + b, -1/2 a + 1/2 c, -1/2 b + 1/2 d, -1/2 c + 1/2 e, -d + e}
In[3]:= ListGradient[{1, 4, 9, 16, 25}, {0, 1, 3, 6, 10}]
Out[3]= {3, 17/6, 73/30, 193/84, 9/4}
Options (2)¶
In[4]:= ListGradient[{{1, 2, 6}, {3, 4, 5}}, Axis -> 2]
Out[4]= {{1, 5/2, 4}, {1, 1, 1}}
In[5]:= ListGradient[{0, 1, 8, 27, 64, 125, 216}, DifferenceOrder -> 4]
Out[5]= {0, 3, 12, 27, 48, 75, 108}
Applications (7)¶
Central differences inside, one-sided at the ends
Symbolic input gives a symbolic gradient
Machine input rides the float buffer
Uniform spacing h = 2
A non-uniform coordinate grid
Rank 2: one array per axis
In[11]:= ListGradient[{{1, 2, 6}, {3, 4, 5}}]
Out[11]= {{{2, 2, -1}, {2, 2, -1}}, {{1, 5/2, 4}, {1, 1, 1}}}
Forward differences everywhere
Options & behaviour¶
Packed arrays.
ListGradientworks straight on afloat64/float32or complex (complex64/complex32) buffer (packed or visibleNDArray), one axis at a time via a strided axpy-style pass — the finite-difference weights are real, so a complex element is just two contiguous doubles carried through the same pass. An integer buffer takes the ordinary path: the central difference of exact integers is aRational(e.g.(f[i+1]-f[i-1])/2) that no buffer holds, so it materialises and the exactListpath answers. Arbitrary-precision (MPFR) and exact (Integer/Rational) arrays likewise compute on the exact/symbolicListpath, retaining full precision.
Implementation notes¶
Algorithm. builtin_list_gradient is a from-first-principles port of
numpy.gradient: the numerical gradient of a sampled rank-k array by finite
differences, one same-shape array per differentiated axis (a rank-1 f gives
one vector, a rank-k f gives {g_1, ..., g_k}). The default reproduces
numpy exactly — a second-order central difference in the interior and a
first-order one-sided difference at the two extreme endpoints (numpy
edge_order = 1). One kernel underlies every Method/order/window/grid
combination: Fornberg's finite-difference-weight recurrence, which returns the
first-derivative weights w[] of f'(x0) ~= sum_k w[k] f(z[k]) on arbitrarily
spaced nodes — so a coordinate vector (a non-uniform grid) needs no special
case. lg_stencil picks the node window per output index: symmetric in the
interior, shifting inward near an edge, and for the Centered method dropping the
two extreme endpoints to a one-sided (m-1)-point stencil; Forward/Backward
stay order p everywhere. Options are Method -> "Centered"|"Forward"|
"Backward", DifferenceOrder -> p (default 2), WindowLength -> m
(default p+1), and Axis -> All | a | {a1, ...}.
Data structures. Two instantiations of the one recurrence.
fd_weights_double drives the machine-buffer fast path — a float64/float32
NDArray, packed or visible; its interior run is a fused tap-outer axpy over the
contiguous block (special-cased for the common 2- and 3-point windows) that the
compiler turns into SIMD FMA, with uniform-spacing weight vectors memoised by
(count, offset). A complex machine buffer is carried through the same real
weights over its interleaved (re, im) doubles. fd_weights_expr builds Expr
weights the evaluator reduces — exact Rationals for an integer/rational grid,
symbolic weights for a symbolic grid — so integer and symbolic inputs answer
exactly. The buffer path declines (returns NULL) for anything it cannot
represent in a float buffer (int64/bool dtype, symbolic spacing), and
ndstruct_delist_repack re-enters the exact/symbolic List path with a
materialised List. On a packed multi-axis call the stacked rank-(k+1) output is
built in place to skip the transparency gate's copy; a visible NDArray keeps the
List-of-arrays shape.
Complexity / limits. O(N * m) for N elements and window m.
ListGradient is on pack.c's AWARE list but deliberately not
INT64_OK: the central difference of exact integers is a Rational
((f[i+1]-f[i-1])/2), which no int64 buffer holds, so an int64 argument
materialises and the exact List path answers. The rank-1 real-array,
default-centered form lowers in Compile[] (compile_ndtables.c) and
auto-compiles. A differentiated axis of length < 2 is undefined and the call
declines.
Protected.- Return shape follows numpy: a rank-1
fgives a single vector; a rank-kfgives{g1, ..., gk}, one same-shape array per axis (ascending axis order); a single requested axis gives one array, not a length-1 list. - Default (
Method -> "Centered",DifferenceOrder -> 2) reproducesnumpy.gradientexactly: an interior point is a second-order central difference and each extreme endpoint a first-order one-sided difference (numpyedge_order = 1— the edge accuracy is one order below the interior). - spacing (numpy's
varargs, as one positional argument): - absent → unit spacing on every axis;
- a scalar (number or symbol) → uniform spacing on every axis;
- a list of one entry per computed axis, each a scalar spacing or a coordinate
vector of that axis's length (non-uniform, exact Fornberg weights). For a
vector, a coordinate list of the same length as
fis used directly. - Options:
Method -> "Centered"(default),"Forward", or"Backward"— the stencil placement. Forward/Backward stay orderpat every point (shifting inward near the far edge); Centered drops the two extreme endpoints to orderp-1.DifferenceOrder -> p(accuracy order, default2).WindowLength -> m(stencil size; defaultAutomatic=p + 1). It is an alias for the order: anm-point stencil is orderm - 1.Axis -> All(default)| a | {a1, ...}— restrict to particular axes (1-based; negatives count from the end).- The single kernel is Fornberg's finite-difference-weight recurrence, exact on
non-uniform grids, so integer input gives exact
Rationals and symbolic input a symbolic result. A machine-Realarray uses the packed/NDArray fast path, andListGradient[v]compiles (rank-1 array form) and auto-compiles.
Attributes: Protected.
References¶
See also: Rational, Real, NDArray, List
- B. Fornberg, Generation of finite difference formulas on arbitrarily spaced grids, Math. Comp. 51 (1988) 699-706.
- Source:
src/list/list_gradient.c - Specification:
docs/spec/builtins/arithmetic.md - Tests:
tests/test_list_gradient.c
Notes & additional examples¶
Notes¶
ListGradient[f] is Mathilda's port of numpy.gradient: it estimates the
derivative of a sampled array by finite differences. By default it uses a
second-order central difference in the interior and a first-order one-sided
difference at the two extreme endpoints, so the result has the same shape as f.
A vector returns a vector; a rank-k array returns {g_1, ..., g_k}, one array
per axis.
Spacing is given by the optional second argument: a scalar h is uniform on
every axis, {s_1, ..., s_k} gives one spec per axis, and a coordinate list the
same length as the axis samples a non-uniform grid — handled with no special
case, because the underlying Fornberg weights are exact on arbitrarily spaced
nodes. Options Method, DifferenceOrder, WindowLength and Axis select the
one-sided variants, the accuracy order, the stencil size, and which axes to
differentiate.
Exactness follows the input: an integer or rational grid yields exact Rationals
((f[i+1]-f[i-1])/2 and friends), a symbolic grid yields symbolic weights, and a
machine-real (or complex) array runs straight on the packed float buffer and
stays packed. Because an integer gradient is Rational and no int64 buffer holds
one, an exact integer input is routed to the List path rather than the buffer.
The rank-1 real-array form also lowers inside Compile[]. Each differentiated
axis must have length at least 2.