Interpolate
public static interpolate ( $source, $args ) : callable | ||
$source | The source of our approximation. Should be either a callback function or a set of arrays. Each array (point) contains precisely two numbers, an x and y. Example array: [[1,2], [2,3], [3,4]]. Example callback: function($x) {return $x**2;} | |
return | callable | The lagrange polynomial p(x) |
/** * Interpolate * * @param $target The point at which we are interpolation * @param $source The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} * @param numbers ... $args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). * * @return number The interpolated value at our target */ public static function interpolate($target, $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 our 0th-degree Lagrange polynomials: Q₍ᵢ₎₍₀₎ = yᵢ for all i < n for ($i = 0; $i < $n; $i++) { $Q[$i][0] = new Polynomial([$sorted[$i][$y]]); // yᵢ } // Recursively generate our (n-1)th-degree Lagrange polynomial at $target 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]($target); $Q₍ᵢ₋₁₎₍ⱼ₋₁₎ = $Q[$i - 1][$j - 1]($target); $Q[$i][$j] = LagrangePolynomial::interpolate([[$xᵢ₋ⱼ, $Q₍ᵢ₋₁₎₍ⱼ₋₁₎], [$xᵢ, $Q₍ᵢ₎₍ⱼ₋₁₎]]); } } // Return our (n-1)th-degree Lagrange polynomial evaluated at $target return $Q[$n - 1][$n - 1]($target); }
/** * Use the Rectangle Method to aproximate the definite integral of a * function f(x). Our input can support either a set of arrays, or a callback * function with arguments (to produce a set of arrays). Each array in our * input contains two numbers which correspond to coordinates (x, y) or * equivalently, (x, f(x)), of the function f(x) whose definite integral we * are approximating. * * The bounds of the definite integral to which we are approximating is * determined by the our inputs. * * Example: approximate([0, 10], [3, 5], [10, 7]) will approximate the definite * integral of the function that produces these coordinates with a lower * bound of 0, and an upper bound of 10. * * Example: approximate(function($x) {return $x**2;}, 0, 4 ,5) will produce * a set of arrays by evaluating the callback at 5 evenly spaced points * between 0 and 4. Then, this array will be used in our approximation. * * Rectangle Rule: * * xn ⁿ⁻¹ xᵢ₊₁ * ∫ f(x)dx = ∑ ∫ f(x)dx * x₁ ⁱ⁼¹ xᵢ * * ⁿ * = ∑ h [f(xᵢ)] + O(h³f″(x)) * ⁱ⁼¹ * * where h = xᵢ₊₁ - xᵢ * note: this implementation does not compute the error term. * @param $source The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} * @param numbers ... $args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). * * @return number The approximation to the integral of f(x) */ 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 = 2); $sorted = self::sort($points); // Descriptive constants $x = self::X; $y = self::Y; // Initialize $n = count($sorted); $steps = $n - 1; $approximation = 0; /* * Summation * ⁿ * = ∑ h [f(xᵢ)] + O(h³f″(x)) * ⁱ⁼¹ * where h = xᵢ₊₁ - xᵢ */ for ($i = 0; $i < $steps; $i++) { $xᵢ = $sorted[$i][$x]; $xᵢ₊₁ = $sorted[$i + 1][$x]; $f⟮xᵢ⟯ = $sorted[$i][$y]; // yᵢ $lagrange = LagrangePolynomial::interpolate([[$xᵢ, $f⟮xᵢ⟯]]); $integral = $lagrange->integrate(); $approximation += $integral($xᵢ₊₁) - $integral($xᵢ); // definite integral of lagrange polynomial } return $approximation; }
/** * Use Simpson's Rule to aproximate the definite integral of a * function f(x). Our input can support either a set of arrays, or a callback * function with arguments (to produce a set of arrays). Each array in our * input contains two numbers which correspond to coordinates (x, y) or * equivalently, (x, f(x)), of the function f(x) whose definite integral we * are approximating. * * Note: Simpson's method requires that we have an even number of * subintervals (we must supply an odd number of points) and also that the * size of each subinterval is equal (spacing between each point is equal). * * The bounds of the definite integral to which we are approximating is * determined by the our inputs. * * Example: approximate([0, 10], [5, 5], [10, 7]) will approximate the definite * integral of the function that produces these coordinates with a lower * bound of 0, and an upper bound of 10. * * Example: approximate(function($x) {return $x**2;}, 0, 4 ,5) will produce * a set of arrays by evaluating the callback at 5 evenly spaced points * between 0 and 4. Then, this array will be used in our approximation. * * Simpson's Rule: * * xn ⁿ⁻¹ xᵢ₊₁ * ∫ f(x)dx = ∑ ∫ f(x)dx * x₁ ⁱ⁼¹ xᵢ * * ⁽ⁿ⁻¹⁾/² h * = ∑ - [f⟮x₂ᵢ₋₁⟯ + 4f⟮x₂ᵢ⟯ + f⟮x₂ᵢ₊₁⟯] + O(h⁵f⁗(x)) * ⁱ⁼¹ 3 * where h = (xn - x₁) / (n - 1) * * @param $source The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4]]. * Example callback: function($x) {return $x**2;} * @param numbers ... $args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 5). * If $source is a set of points, do not input any * $args. Example: approximate($source). * * @return number The approximation to the integral of f(x) */ 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 = 3); Validation::isSubintervalsMultiple($points, $m = 2); $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; /* * Summation * ⁽ⁿ⁻¹⁾/² h * ∑ - [f⟮x₂ᵢ₋₁⟯ + 4f⟮x₂ᵢ⟯ + f⟮x₂ᵢ₊₁⟯] + O(h⁵f⁗(x)) * ⁱ⁼¹ 3 * where h = (xn - x₁) / (n - 1) */ for ($i = 1; $i < $subintervals / 2 + 1; $i++) { $x₂ᵢ₋₁ = $sorted[2 * $i - 2][$x]; $x₂ᵢ = $sorted[2 * $i - 1][$x]; $x₂ᵢ₊₁ = $sorted[2 * $i][$x]; $f⟮x₂ᵢ₋₁⟯ = $sorted[2 * $i - 2][$y]; // y₂ᵢ₋₁ $f⟮x₂ᵢ⟯ = $sorted[2 * $i - 1][$y]; // y₂ᵢ $f⟮x₂ᵢ₊₁⟯ = $sorted[2 * $i][$y]; // y₂ᵢ₊₁ $lagrange = LagrangePolynomial::interpolate([[$x₂ᵢ₋₁, $f⟮x₂ᵢ₋₁⟯], [$x₂ᵢ, $f⟮x₂ᵢ⟯], [$x₂ᵢ₊₁, $f⟮x₂ᵢ₊₁⟯]]); $integral = $lagrange->integrate(); $approximation += $integral($x₂ᵢ₊₁) - $integral($x₂ᵢ₋₁); // definite integral of lagrange polynomial } return $approximation; }
/** * Use Boole's Rule to aproximate the definite integral of a * function f(x). Our input can support either a set of arrays, or a callback * function with arguments (to produce a set of arrays). Each array in our * input contains two numbers which correspond to coordinates (x, y) or * equivalently, (x, f(x)), of the function f(x) whose definite integral we * are approximating. * * Note: Boole's rule requires that our number of subintervals is a factor * of four (we must supply an n points such that n-1 is a multiple of four) * and also that the size of each subinterval is equal (spacing between each * point is equal). * * The bounds of the definite integral to which we are approximating is * determined by the our inputs. * * Example: approximate([0, 10], [2, 5], [4, 7], [6,3]) will approximate the * definite integral of the function that produces these coordinates with a * lower bound of 0, and an upper bound of 6. * * Example: approximate(function($x) {return $x**2;}, [0, 3 ,5]) will produce * a set of arrays by evaluating the callback at 5 evenly spaced points * between 0 and 3. Then, this array will be used in our approximation. * * Boole's Rule: * * xn ⁿ⁻¹ xᵢ₊₁ * ∫ f(x)dx = ∑ ∫ f(x)dx * x₁ ⁱ⁼¹ xᵢ * * ⁽ⁿ⁻¹⁾/⁴ 2h * = ∑ -- [7f⟮x₄ᵢ₋₃⟯ + 32f⟮x₄ᵢ₋₂⟯ + 12f⟮x₄ᵢ₋₁⟯ + 32f⟮x₄ᵢ⟯ + 7f⟮x₄ᵢ₊₁⟯] + O(h⁷f⁽⁶⁾(x)) * ⁱ⁼¹ 45 * where h = (xn - x₁) / (n - 1) * * @param $source The source of our approximation. Should be either * a callback function or a set of arrays. Each array * (point) contains precisely two numbers, an x and y. * Example array: [[1,2], [2,3], [3,4], [4,5], [5,6]]. * Example callback: function($x) {return $x**2;} * @param numbers ... $args The arguments of our callback function: start, * end, and n. Example: approximate($source, 0, 8, 4). * If $source is a set of points, do not input any * $args. Example: approximate($source). * * @return number The approximation to the integral of f(x) */ 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; }