public static function interpolate($source, ...$args)
{
// get an array of points from our $source argument
$points = self::getPoints($source, $args);
// Validate input and sort points
self::validate($points, $degree = 2);
$sorted = self::sort($points);
// Descriptive constants
$x = self::X;
$y = self::Y;
// Initialize
$n = count($sorted);
$Q = [];
// Build first column of divided differences table
for ($i = 0; $i < $n; $i++) {
$Q[$i][0] = $sorted[$i][$y];
// yᵢ
}
// Recursively generate remaining columns of our divided difference table
for ($i = 1; $i < $n; $i++) {
for ($j = 1; $j <= $i; $j++) {
$xᵢ₋ⱼ = $sorted[$i - $j][$x];
$xᵢ = $sorted[$i][$x];
$Q₍ᵢ₎₍ⱼ₋₁₎ = $Q[$i][$j - 1];
$Q₍ᵢ₋₁₎₍ⱼ₋₁₎ = $Q[$i - 1][$j - 1];
$Q[$i][$j] = ($Q₍ᵢ₎₍ⱼ₋₁₎ - $Q₍ᵢ₋₁₎₍ⱼ₋₁₎) / ($xᵢ - $xᵢ₋ⱼ);
}
}
// initialize empty polynomial
$polynomial = new Polynomial([0]);
for ($i = 0; $i < $n; $i++) {
// start each product with the upper diagonal from our divideded differences table
$product = new Polynomial([$Q[$i][$i]]);
for ($j = 1; $j <= $i; $j++) {
// generate the (x - xⱼ₋₁) term for each j
//$term = function ($t) use ($sorted, $x, $i, $j) {
// return ($t - $sorted[$j-1][$x]);
//};
$term = new Polynomial([1, -$sorted[$j - 1][$x]]);
// multiply the term and our cumulative product
$product = $product->multiply($term);
}
// add the whole product to our polynomial for each i
$polynomial = $polynomial->add($product);
}
return $polynomial;
}