MathPHP\NumericalAnalysis\Interpolation\ClampedCubicSpline::interpolate PHP Метод

interpolate() публичный статический Метод

Interpolate
public static interpolate ( $source, $args ) : Piecewise
$source The source of our approximation. Should be either a callback function or a set of arrays. Each array (point) contains precisely three numbers: x, y, and y' Example array: [[1,2,1], [2,3,0], [3,4,2]]. Example callback: function($x) {return $x**2;}
Результат MathPHP\Functions\Piecewise The interpolting (piecewise) polynomial, as an instance of Piecewise.
    public static function interpolate($source, ...$args)
    {
        // Get an array of points from our $source argument
        $points = self::getSplinePoints($source, $args);
        // Validate input and sort points
        self::validateSpline($points, $degree = 1);
        $sorted = self::sort($points);
        // Descriptive constants
        $x = self::X;
        $y = self::Y;
        $y’ = self::Y’;
        // Initialize
        $n = count($sorted);
        $k = $n - 1;
        $x₀ = $sorted[0][$x];
        $x₁ = $sorted[1][$x];
        $f⟮x₀⟯ = $sorted[0][$y];
        // y₀
        $f⟮x₁⟯ = $sorted[1][$y];
        // y₁
        $y’₀ = $sorted[0][$y’];
        // y₀-prime
        $h = [$x₁ - $x₀];
        $a = [3 / $h[0] * ($f⟮x₁⟯ - $f⟮x₀⟯) - 3 * $y’₀];
        $μ = [0.5];
        $z = [$a[0] / (2 * $h[0])];
        $c[$k] = 0;
        $poly = [];
        for ($i = 0; $i < $k; $i++) {
            $xᵢ = $sorted[$i][$x];
            $xᵢ₊₁ = $sorted[$i + 1][$x];
            $a[$i] = $sorted[$i][$y];
            $h[$i] = $xᵢ₊₁ - $xᵢ;
            if ($i == 0) {
                continue;
            }
            $xᵢ₋₁ = $sorted[$i - 1][$x];
            $f⟮xᵢ⟯ = $sorted[$i][$y];
            // yᵢ
            $f⟮xᵢ₊₁⟯ = $sorted[$i + 1][$y];
            // yᵢ₊₁
            $f⟮xᵢ₋₁⟯ = $sorted[$i - 1][$y];
            // yᵢ₋₁
            $α = 3 / $h[$i] * ($f⟮xᵢ₊₁⟯ - $f⟮xᵢ⟯) - 3 / $h[$i - 1] * ($f⟮xᵢ⟯ - $f⟮xᵢ₋₁⟯);
            $l = 2 * ($xᵢ₊₁ - $xᵢ₋₁) - $h[$i - 1] * $μ[$i - 1];
            $μ[$i] = $h[$i] / $l;
            $z[$i] = ($α - $h[$i - 1] * $z[$i - 1]) / $l;
        }
        $f⟮xₙ⟯ = $sorted[$k][$y];
        // yₙ
        $f⟮xₙ₋₁⟯ = $sorted[$k - 1][$y];
        // yₙ₋₁
        $y’ₙ = $sorted[$k][$y’];
        // yₙ-prime
        $a[$k] = 3 * $y’ₙ - 3 * ($f⟮xₙ⟯ - $f⟮xₙ₋₁⟯) / $h[$k - 1];
        $l = $h[$k - 1] * (2 - $μ[$k - 1]);
        $z[$k] = ($a[$k] - $h[$k - 1] * $z[$k - 1]) / $l;
        $c[$n] = $z[$k];
        for ($i = $k - 1; $i >= 0; $i--) {
            $xᵢ = $sorted[$i][$x];
            $xᵢ₊₁ = $sorted[$i + 1][$x];
            $f⟮xᵢ⟯ = $sorted[$i][$y];
            // yᵢ
            $f⟮xᵢ₊₁⟯ = $sorted[$i + 1][$y];
            // yᵢ₊₁
            $c[$i] = $z[$i] - $μ[$i] * $c[$i + 1];
            $b[$i] = ($f⟮xᵢ₊₁⟯ - $f⟮xᵢ⟯) / $h[$i] - $h[$i] * ($c[$i + 1] + 2 * $c[$i]) / 3;
            $d[$i] = ($c[$i + 1] - $c[$i]) / (3 * $h[$i]);
            $poly[$i] = new Polynomial([$d[$i], $c[$i] - 3 * $d[$i] * $xᵢ, $b[$i] - 2 * $c[$i] * $xᵢ + 3 * $d[$i] * $xᵢ ** 2, $a[$i] - $b[$i] * $xᵢ + $c[$i] * $xᵢ ** 2 - $d[$i] * $xᵢ ** 3]);
            if ($i == 0) {
                $int[$i] = [$xᵢ, $xᵢ₊₁];
            } else {
                $int[$i] = [$xᵢ, $xᵢ₊₁, true, false];
            }
        }
        $piecewise = new Piecewise($int, $poly);
        return $piecewise;
    }

Usage Example

 public function testSolveNonzeroError()
 {
     // f(x) = x⁴ + 8x³ -13x² -92x + 96
     $f = new Polynomial([1, 8, -13, -92, 96]);
     $f’ = $f->differentiate();
     $f⁽⁴⁾ = $f’->differentiate()->differentiate()->differentiate();
     // The error is bounded by:
     // |f(x)-p(x)| = tol <= (5/384) * h⁴ * max f⁽⁴⁾(x)
     // where h = max hᵢ
     // and max f⁽⁴⁾(x) = f⁽⁴⁾(x) for all x given a 4th-degree polynomial f(x)
     $a = 0;
     $b = 10;
     $n = 51;
     // So, tol <= (1/24) * (1/5)⁴ * 24 = (1/5)⁴
     $h = ($b - $a) / ($n - 1);
     $tol = 5 / 384 * $h ** 4 * $f⁽⁴⁾(0);
     $roundoff = 1.0E-6;
     // round off error
     $p = ClampedCubicSpline::interpolate($f, $f’, $a, $b, $n);
     // Check that p(x) agrees with f(x) at x = 0
     $target = 0;
     $expected = $f($target);
     $x = $p($target);
     $this->assertEquals($expected, $x, '', $tol + $roundoff);
     // Check that p(x) agrees with f(x) at x = 2
     $target = 2;
     $expected = $f($target);
     $x = $p($target);
     $this->assertEquals($expected, $x, '', $tol + $roundoff);
     // Check that p(x) agrees with f(x) at x = 4
     $target = 4;
     $expected = $f($target);
     $x = $p($target);
     $this->assertEquals($expected, $x, '', $tol + $roundoff);
     // Check that p(x) agrees with f(x) at x = 6
     $target = 6;
     $expected = $f($target);
     $x = $p($target);
     $this->assertEquals($expected, $x, '', $tol + $roundoff);
     // Check that p(x) agrees with f(x) at x = 8
     $target = 8;
     $expected = $f($target);
     $x = $p($target);
     $this->assertEquals($expected, $x, '', $tol + $roundoff);
     // Check that p(x) agrees with f(x) at x = 10
     $target = 10;
     $expected = $f($target);
     $x = $p($target);
     $this->assertEquals($expected, $x, '', $tol + $roundoff);
     // Check that p(x) agrees with f(x) at x = 7.32 (not a node)
     $target = 7.32;
     $expected = $f($target);
     $x = $p($target);
     $this->assertEquals($expected, $x, '', $tol + $roundoff);
 }