Source code for dualbounds.interpolation
"""
Contains various interpolation functions used to
go from discrete dual variables to continuous ones.
"""
import numpy as np
import scipy as sp
from . import utilities
[docs]
def adaptive_interpolate(x: np.array, y: np.array, newx: np.array):
"""
Adaptively chooses between linear and nearest-neighbor
interpolation.
Parameters
----------
x : np.array
n-length array of inputs. Must be sorted, although
this is not explicitly enforced to save time.
y : np.array
n-length array of outputs
newx : np.array
m-length array of new inputs
Returns
-------
newy : np.array
m-length array of interpolated outputs
"""
if len(np.unique(y)) <= 2 and len(y) > 2:
return nn_interpolate(x, y, newx)
else:
return linear_interpolate(x, y, newx)
[docs]
def nn_interpolate(x: np.array, y: np.array, newx: np.array):
"""
Nearest-neighbor interpolation.
Parameters
----------
x : np.array
n-length array of inputs. Must be sorted, although
this is not explicitly enforced to save time.
y : np.array
n-length array of outputs
newx : np.array
m-length array of new inputs
Returns
-------
newy : np.array
m-length array of interpolated outputs
"""
# Find nearest neighbors
if not utilities.haslength(newx):
newx = np.array([newx])
n = len(x)
rinds = np.minimum(np.searchsorted(x, newx, side='left'), n-1)
linds = np.maximum(rinds-1, 0)
inds = np.stack([linds, rinds], axis=1)
dists = np.abs(x[inds] - newx.reshape(-1, 1))
nbrs = inds[(np.arange(len(newx)), np.argmin(dists, axis=1))]
# Return
return y[nbrs]
[docs]
def linear_interpolate(x: np.array, y: np.array, newx: np.array):
"""
Linear interpolation.
Parameters
----------
x : np.array
n-length array of inputs. Must be sorted, although
this is not explicitly enforced to save time.
y : np.array
n-length array of outputs
newx : np.array
m-length array of new inputs
Returns
-------
newy : np.array
m-length array of interpolated outputs
"""
if not utilities.haslength(newx):
newx = np.array([newx])
# for now, check sorting (TODO DELETE)
# if np.any(np.sort(x) != x):
# raise ValueError("NOT SORTED")
# interpolate points in the range of x
haty = np.interp(newx, x, y)
# Check if there are any points outside the boundaries
lflags = newx < x[0]
uflags = newx > x[-1]
if not (np.any(lflags) or np.any(uflags)):
return haty
# Prevent div by 0 errors/warnings
x, index = np.unique(x, return_index=True)
y = y[index]
# adjust for points < x.min()
ldx = (y[1] - y[0]) / (x[1] - x[0])
haty[lflags] = y[0] + (newx[lflags] - x[0]) * ldx
# adjust for points > x.max()
udx = (y[-1] - y[-2]) / (x[-1] - x[-2])
haty[uflags] = y[-1] + (newx[uflags] - x[-1]) * udx
return haty
def spline_interpolate(
x, y, newx
):
if not utilities.haslength(newx):
newx = np.array([newx])
spline_rep = sp.interpolate.splrep(x=x, y=y)
return sp.interpolate.splev(newx, spline_rep)