Skip to content

Instantly share code, notes, and snippets.

@ezheidtmann
Created April 22, 2022 19:27
Show Gist options
  • Save ezheidtmann/854b9a00a5e15bf5c4a7e67e1fcece1b to your computer and use it in GitHub Desktop.
Save ezheidtmann/854b9a00a5e15bf5c4a7e67e1fcece1b to your computer and use it in GitHub Desktop.
Linear Interpolated Function in Python and Swift
from operator import itemgetter
from typing import List, NamedTuple, Tuple
from common.pairwise import pairwise
class XY(NamedTuple):
x: float
y: float
class LinearInterpolatedFunction:
pts: List[XY]
xmax: float
ymax: float
def __init__(self, control_points: List[Tuple[float, float]]) -> None:
self.pts = [XY(*val) for val in sorted(control_points, key=itemgetter(0))]
self.xmin = self.pts[0].x
self.xmax = self.pts[-1].x
def __call__(self, desired_x: float) -> float:
if desired_x >= self.xmax:
return self.pts[-1].y
if desired_x <= self.xmin:
return self.pts[0].y
for (x1, y1), (x2, y2) in pairwise(self.pts):
if x1 <= desired_x <= x2:
return y1 + (desired_x - x1) * (y2 - y1) / (x2 - x1)
T = TypeVar("T")
def pairwise(iterable: Iterable[T]) -> Iterable[Tuple[T, T]]:
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
import Foundation
fileprivate extension Collection {
subscript(back i: Int) -> Iterator.Element {
let backBy = i + 1
return self[self.index(self.endIndex, offsetBy: -backBy)]
}
}
class LinearInterpolatedFunction {
private let _pts: [(x: Double, y: Double)]
private let _xmax: Double
private let _xmin: Double
/**
Initialize function with control points
Control points is a list of (x, y) tuples. The function will have slope 0 for values outside the specified points.
*/
init(_ controlPoints: [(x: Double, y: Double)]) {
_pts = controlPoints.sorted(by: { (arg0, arg1) in
return arg0.x < arg1.x
})
_xmin = _pts[0].x
_xmax = _pts[back: 0].x
}
func evaluate(_ x: Double) -> Double {
if x >= _xmax {
return _pts[back: 0].y
}
if x <= _xmin {
return _pts[0].y
}
let belowIndex = _pts.lastIndex { item in
item.x <= x
}!
let low = _pts[belowIndex]
let high = _pts[belowIndex+1]
return low.y + (x-low.x) * (high.y-low.y) / (high.x - low.x)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment