public static function approximate($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 = 5);
Validation::isSubintervalsMultiple($points, $m = 4);
$sorted = self::sort($points);
Validation::isSpacingConstant($sorted);
// Descriptive constants
$x = self::X;
$y = self::Y;
// Initialize
$n = count($sorted);
$subintervals = $n - 1;
$a = $sorted[0][$x];
$b = $sorted[$n - 1][$x];
$h = ($b - $a) / $subintervals;
$approximation = 0;
/*
* ⁽ⁿ⁻¹⁾/⁴ 2h
* = ∑ -- [7f⟮x₄ᵢ₋₃⟯ + 32f⟮x₄ᵢ₋₂⟯ + 12f⟮x₄ᵢ₋₁⟯ + 32f⟮x₄ᵢ⟯ + 7f⟮x₄ᵢ₊₁⟯] + O(h⁷f⁽⁶⁾(x))
* ⁱ⁼¹ 45
*/
for ($i = 1; $i < $subintervals / 4 + 1; $i++) {
$x₄ᵢ₋₃ = $sorted[4 * $i - 4][$x];
$x₄ᵢ₋₂ = $sorted[4 * $i - 3][$x];
$x₄ᵢ₋₁ = $sorted[4 * $i - 2][$x];
$x₄ᵢ = $sorted[4 * $i - 1][$x];
$x₄ᵢ₊₁ = $sorted[4 * $i][$x];
$f⟮x₄ᵢ₋₃⟯ = $sorted[4 * $i - 4][$y];
// y₄ᵢ₋₃
$f⟮x₄ᵢ₋₂⟯ = $sorted[4 * $i - 3][$y];
// y₄ᵢ₋₂
$f⟮x₄ᵢ₋₁⟯ = $sorted[4 * $i - 2][$y];
// y₄ᵢ₋₁
$f⟮x₄ᵢ⟯ = $sorted[4 * $i - 1][$y];
// y₄ᵢ
$f⟮x₄ᵢ₊₁⟯ = $sorted[4 * $i][$y];
// y₄ᵢ₊₁
$lagrange = LagrangePolynomial::interpolate([[$x₄ᵢ₋₃, $f⟮x₄ᵢ₋₃⟯], [$x₄ᵢ₋₂, $f⟮x₄ᵢ₋₂⟯], [$x₄ᵢ₋₁, $f⟮x₄ᵢ₋₁⟯], [$x₄ᵢ, $f⟮x₄ᵢ⟯], [$x₄ᵢ₊₁, $f⟮x₄ᵢ₊₁⟯]]);
$integral = $lagrange->integrate();
$approximation += $integral($x₄ᵢ₊₁) - $integral($x₄ᵢ₋₃);
// definite integral of lagrange polynomial
}
return $approximation;
}