/** * 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; }
/** * Use Simpson's 3/8 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 3/8 rule requires that our number of subintervals is a factor * of three (we must supply an n points such that n-1 is a multiple of three) * 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 ,4]) will produce * a set of arrays by evaluating the callback at 4 evenly spaced points * between 0 and 3. Then, this array will be used in our approximation. * * Simpson's 3/8 Rule: * * xn ⁿ⁻¹ xᵢ₊₁ * ∫ f(x)dx = ∑ ∫ f(x)dx * x₁ ⁱ⁼¹ xᵢ * * ⁽ⁿ⁻¹⁾/³ 3h * = ∑ - [f⟮x₂ᵢ₋₁⟯ + 3f⟮x₂ᵢ⟯ + 3f⟮x₂ᵢ₊₁⟯ + f⟮x₂ᵢ₊₂⟯] + O(h⁵f⁗(x)) * ⁱ⁼¹ 8 * 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]]. * 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 = 4); Validation::isSubintervalsMultiple($points, $m = 3); $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; /* * ⁽ⁿ⁻¹⁾/³ 3h * ∑ -- [f⟮x₂ᵢ₋₁⟯ + 3f⟮x₂ᵢ⟯ + 3f⟮x₂ᵢ₊₁⟯ + f⟮x₂ᵢ₊₂⟯] + O(h⁵f⁗(x)) * ⁱ⁼¹ 8 * where h = (xn - x₁) / (n - 1) */ for ($i = 1; $i < $subintervals / 3 + 1; $i++) { $x₂ᵢ₋₁ = $sorted[2 * $i - 2][$x]; $x₂ᵢ = $sorted[2 * $i - 1][$x]; $x₂ᵢ₊₁ = $sorted[2 * $i][$x]; $x₂ᵢ₊₂ = $sorted[2 * $i + 1][$x]; $f⟮x₂ᵢ₋₁⟯ = $sorted[2 * $i - 2][$y]; // y₂₋₁ $f⟮x₂ᵢ⟯ = $sorted[2 * $i - 1][$y]; // y₂ᵢ $f⟮x₂ᵢ₊₁⟯ = $sorted[2 * $i][$y]; // y₂ᵢ₊₁ $f⟮x₂ᵢ₊₂⟯ = $sorted[2 * $i + 1][$y]; // y₂ᵢ₊₂ $lagrange = LagrangePolynomial::interpolate([[$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; }