import numpy as np
[docs]
def relative_error_within_boundaries(x: np.array, low: np.array, high: np.array) -> np.array: # type: ignore
"""
Calculate the relative error of values within specified boundaries.
Args:
x (np.array): The array of values.
low (np.array): The lower boundary array.
high (np.array): The upper boundary array.
Returns:
np.array: The array of relative errors.
"""
return np.abs(error_within_boundaries(x, low, high))/x
[docs]
def error_within_boundaries(x: np.array, low: np.array, high: np.array) -> np.array: # type: ignore
"""
Calculate the error of values within specified boundaries.
Args:
x (np.array): The array of values.
low (np.array): The lower boundary array.
high (np.array): The upper boundary array.
Returns:
np.array: The array of errors.
"""
nearest_boundary = np.where(x < low, low, np.where(x > high, high, x))
return x - nearest_boundary
[docs]
def clipped_cumsum(a: np.ndarray, xmin=-np.inf, xmax=np.inf):
"""Compute a cumulative sum along the first axis with clipping.
This function computes the cumulative sum of `a` along the first axis
(rows). After adding each row, intermediate cumulative values are
clipped to the interval [xmin, xmax]. The clipping is applied elementwise
across columns for 2-D input. The function preserves the input shape:
- If `a` is 1-D, it is treated as a single column and the result is a
1-D array of the same shape.
- If `a` is 2-D (shape (n_steps, n_series)), the cumulative sum is
computed independently for each column and the result has the same
shape as `a`.
Parameters
----------
a : np.ndarray
Input array. Expected shape is (n_steps,) or (n_steps, n_series).
The cumulative sum is performed along axis 0.
xmin : float, optional
Minimum allowed cumulative value (inclusive). Defaults to -inf.
xmax : float, optional
Maximum allowed cumulative value (inclusive). Defaults to +inf.
Returns
-------
np.ndarray
Array of the same shape as `a` containing the clipped cumulative sums.
Notes
-----
- The function uses an internal accumulator initialized to zeros with
length equal to the number of columns (1 for 1-D input).
- Clipping is applied elementwise after each accumulation step using
`np.minimum` and `np.maximum` so values stay within [xmin, xmax].
Examples
--------
>>> import numpy as np
>>> a = np.array([1, 2, -1, 5])
>>> clipped_cumsum(a, xmin=0, xmax=5)
array([1, 3, 2, 5])
>>> b = np.array([[1, 0], [2, 3], [4, -2]])
>>> clipped_cumsum(b, xmin=-1, xmax=4)
array([[ 1, 0],
[ 3, 3],
[ 4, 1]])
"""
input_dim = a.ndim
if input_dim == 1:
a = a[:, np.newaxis]
res = np.empty_like(a)
c = np.zeros(a.shape[1])
for i in range(len(a)):
c = np.minimum(np.maximum(c + a[i, :], xmin), xmax)
res[i, :] = c
if input_dim == 1:
res = res[:, 0]
return res