interpolate() public static method

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)
Exemplo n.º 1
0
 /**
  * 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);
 }
Exemplo n.º 2
0
 /**
  * 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;
 }
Exemplo n.º 3
0
 /**
  * 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;
 }
Exemplo n.º 4
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;
 }