예제 #1
0
 /**
  * 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;
 }