Spaces:
Running
on
Zero
Running
on
Zero
from typing import * | |
import numpy as np | |
__all__ = ['linear_spline_interpolate'] | |
def linear_spline_interpolate(x: np.ndarray, t: np.ndarray, s: np.ndarray, extrapolation_mode: Literal['constant', 'linear'] = 'constant') -> np.ndarray: | |
""" | |
Linear spline interpolation. | |
### Parameters: | |
- `x`: np.ndarray, shape (n, d): the values of data points. | |
- `t`: np.ndarray, shape (n,): the times of the data points. | |
- `s`: np.ndarray, shape (m,): the times to be interpolated. | |
- `extrapolation_mode`: str, the mode of extrapolation. 'constant' means extrapolate the boundary values, 'linear' means extrapolate linearly. | |
### Returns: | |
- `y`: np.ndarray, shape (..., m, d): the interpolated values. | |
""" | |
i = np.searchsorted(t, s, side='left') | |
if extrapolation_mode == 'constant': | |
prev = np.clip(i - 1, 0, len(t) - 1) | |
suc = np.clip(i, 0, len(t) - 1) | |
elif extrapolation_mode == 'linear': | |
prev = np.clip(i - 1, 0, len(t) - 2) | |
suc = np.clip(i, 1, len(t) - 1) | |
else: | |
raise ValueError(f'Invalid extrapolation_mode: {extrapolation_mode}') | |
u = (s - t[prev]) / np.maximum(t[suc] - t[prev], 1e-12) | |
y = u * x[suc] + (1 - u) * x[prev] | |
return y | |
def _solve_tridiagonal(a: np.ndarray, b: np.ndarray, c: np.ndarray, d: np.ndarray) -> np.ndarray: | |
n = b.shape[-1] | |
cc = np.zeros_like(b) | |
dd = np.zeros_like(b) | |
cc[..., 0] = c[..., 0] / b[..., 0] | |
dd[..., 0] = d[..., 0] / b[..., 0] | |
for i in range(1, n): | |
cc[..., i] = c[..., i] / (b[..., i] - a[..., i - 1] * cc[..., i - 1]) | |
dd[..., i] = (d[..., i] - a[..., i - 1] * dd[..., i - 1]) / (b[..., i] - a[..., i - 1] * cc[..., i - 1]) | |
x = np.zeros_like(b) | |
x[..., -1] = dd[..., -1] | |
for i in range(n - 2, -1, -1): | |
x[..., i] = dd[..., i] - cc[..., i] * x[..., i + 1] | |
return x | |
def cubic_spline_interpolate(x: np.ndarray, t: np.ndarray, s: np.ndarray, v0: np.ndarray = None, vn: np.ndarray = None) -> np.ndarray: | |
""" | |
Cubic spline interpolation. | |
### Parameters: | |
- `x`: np.ndarray, shape (..., n,): the x-coordinates of the data points. | |
- `t`: np.ndarray, shape (n,): the knot vector. NOTE: t must be sorted in ascending order. | |
- `s`: np.ndarray, shape (..., m,): the y-coordinates of the data points. | |
- `v0`: np.ndarray, shape (...,): the value of the derivative at the first knot, as the boundary condition. If None, it is set to zero. | |
- `vn`: np.ndarray, shape (...,): the value of the derivative at the last knot, as the boundary condition. If None, it is set to zero. | |
### Returns: | |
- `y`: np.ndarray, shape (..., m): the interpolated values. | |
""" | |
h = t[..., 1:] - t[..., :-1] | |
mu = h[..., :-1] / (h[..., :-1] + h[..., 1:]) | |
la = 1 - mu | |
d = (x[..., 1:] - x[..., :-1]) / h | |
d = 6 * (d[..., 1:] - d[..., :-1]) / (t[..., 2:] - t[..., :-2]) | |
mu = np.concatenate([mu, np.ones_like(mu[..., :1])], axis=-1) | |
la = np.concatenate([np.ones_like(la[..., :1]), la], axis=-1) | |
d = np.concatenate([(((x[..., 1] - x[..., 0]) / h[0] - v0) / h[0])[..., None], d, ((vn - (x[..., -1] - x[..., -2]) / h[-1]) / h[-1])[..., None]], axis=-1) | |
M = _solve_tridiagonal(mu, np.full_like(d, fill_value=2), la, d) | |
i = np.searchsorted(t, s, side='left') | |