normalized_difference¶
- normalized_difference(a, b)[source]¶
Compute normalized difference (a - b) / (a + b) using the Rust core. Supports 1D or 2D numpy float arrays; dimensional dispatch occurs in Rust.
Overview¶
normalized_difference(a, b) computes the element‑wise ratio:
with an internal near‑zero (EPSILON = 1e-10) safeguard. When the denominator a + b has absolute value less than EPSILON the output for that element is set to 0.0 to avoid unstable large magnitudes or division by zero.
Dimensional Support¶
This function supports 1D, 2D, 3D, and 4D numeric NumPy arrays (all input dtypes are coerced to float64 internally). Shapes for a and b must match exactly.
Typical axis interpretations (not enforced; purely numeric): - 1D: spectral samples or time series - 2D: image or (samples, features) - 3D: (time, y, x) or (band, y, x) depending on upstream layout - 4D: (time, band, y, x) or other structured stacks
Input Rules¶
Both inputs must be NumPy arrays with identical shape.
Any numeric dtype is accepted; coercion to float64 occurs before computation.
NaNs propagate: if either element is NaN, the corresponding result element becomes NaN unless later post‑processing masks or replaces them.
Output¶
A float64 NumPy array of the same shape as a and b.
Numerical Stability¶
Small denominators: if |a + b| < 1e-10, the output element is set to 0.0.
This avoids extreme values for near‑cancelling inputs.
Performance Notes¶
Implemented in Rust using the
ndarraycrate with fused iteration (no intermediate arrays).GIL is released during execution.
For larger arrays (particularly 3D/4D) memory access is sequential, improving cache locality compared to chained pure NumPy expressions
(a - b) / (a + b)which create 2 temporaries.
Examples¶
Basic 1D usage:
import numpy as np
from eo_processor import normalized_difference
nir = np.array([0.8, 0.7, 0.6])
red = np.array([0.2, 0.1, 0.3])
ndvi_like = normalized_difference(nir, red)
print(ndvi_like)
2D image:
import numpy as np
from eo_processor import normalized_difference
a = np.random.rand(512, 512)
b = np.random.rand(512, 512)
nd = normalized_difference(a, b)
assert nd.shape == a.shape
4D stack (e.g., (time, band, y, x)):
import numpy as np
from eo_processor import normalized_difference
a = np.random.rand(4, 3, 128, 128)
b = np.random.rand(4, 3, 128, 128)
out = normalized_difference(a, b)
assert out.shape == (4, 3, 128, 128)
Edge case with near‑zero denominator:
import numpy as np
from eo_processor import normalized_difference
a = np.array([1e-12, 0.5])
b = np.array([-1e-12, 0.5])
# First pair sums to ~0 → safeguarded to 0.0
out = normalized_difference(a, b)
print(out) # [0.0, 0.0]
Error Handling¶
Raises ValueError if shapes differ.
Raises TypeError if inputs cannot be interpreted as 1D–4D numeric arrays.
Testing Guarantees¶
The test suite validates:
- Correct equality with manual (a - b) / (a + b) for standard arrays.
- Antisymmetry: normalized_difference(a, b) == -normalized_difference(b, a).
- Zero safeguarding behavior.
- Range adherence for index derivatives (e.g., NDVI bounds in dedicated tests).
Notes¶
For spectral index semantics (NDVI, NDWI, etc.) prefer the dedicated named helpers; normalized_difference is ideal for generic band math or custom ratio experimentation.
End of normalized_difference reference.