ore_algebra.analytic.polynomial_approximation

Rigorous approximation of D-finite functions by polynomials

Functions

chebyshev_economization(pol, eps) Decrease the degree of pol in such a way that its value on the real segment [-1, 1] changes at most by eps.
chebyshev_polynomials(ring, n) Return the list of the Chebyshev polynomials T[0], …, T[n-1] as elements of ring.
combine_radii(pol)
doit(dop, ini, path, rad, eps, derivatives, …)
general_economization(…) Decrease the degree of pol by subtracting a linear combination of the polynomials produced by economization_polynomials.
mixed_economization()
on_disk(dop, ini, path, rad, eps) Compute a polynomial approximation of a solution of dop on a complex disk.
on_interval(dop, ini, path, eps[, rad]) Compute a polynomial approximation of a solution of dop on a segment.
taylor_economization(pol, eps) Economize a polynomial by removing monomials.
ore_algebra.analytic.polynomial_approximation.chebyshev_economization(pol, eps)

Decrease the degree of pol in such a way that its value on the real segment [-1, 1] changes at most by eps.

EXAMPLES:

sage: from ore_algebra.analytic.polynomial_approximation import chebyshev_economization
sage: pol = polygen(QQ, 'x')._exp_series(10).change_ring(RBF)
sage: newpol = chebyshev_economization(pol, RBF(1e-3)); newpol
[0.04379...]*x^4 + [0.17734...]*x^3 + [0.49919...]*x^2 + [0.9973...]*x +
[1.000 +/- 6...e-4]

TESTS:

sage: from ore_algebra.analytic.polynomial_approximation import _test_fun_approx
sage: _test_fun_approx(newpol, pol, interval_rad=1)
ore_algebra.analytic.polynomial_approximation.chebyshev_polynomials(ring, n)

Return the list of the Chebyshev polynomials T[0], …, T[n-1] as elements of ring.

EXAMPLES:

sage: from ore_algebra.analytic.polynomial_approximation import chebyshev_polynomials
sage: chebyshev_polynomials(ZZ['x'], 3)
[1, x, 2*x^2 - 1]

TESTS:

sage: chebyshev_polynomials(QQ['x'], 0)
[]
ore_algebra.analytic.polynomial_approximation.general_economization(economization_polynomials, pol, eps)

Decrease the degree of pol by subtracting a linear combination of the polynomials produced by economization_polynomials.

INPUT:

  • economization_polynomials(ring, n) - function returning a list [E[0], …, E[n-1]] of n elements of ring; it is assumed that E[k] is a polynomial of degree exactly k such that |E[k](x)| ≤ 1 when x lies in some domain of interest;
  • pol - polynomial with real or complex ball coefficients;
  • eps - real ball, maximum error that may be added to the polynomial (see below).

OUTPUT:

A polynomial with the same parent as pol. A bound on the linear combination of economization polynomials is added to the constant term. For real x in the domain where they are all bounded by 1, the value of the result at x contains that of pol. This also holds true for complex x when pol has complex coefficients, but not in general for the evaluation at complex points of polynomials with real coefficients.

TESTS:

sage: from ore_algebra.analytic.polynomial_approximation import general_economization
sage: def monomials(ring, n):
....:     x = ring.gen()
....:     return [x**k for k in range(n)]
sage: Pols.<x> = RBF[]
sage: general_economization(monomials,
....:         x^5 + 10*x^4 + x^3 + 2*x + 10, RBF(3))
10.00000000000000*x^4 + 2.000000000000000*x + [1e+1 +/- 2.01]
ore_algebra.analytic.polynomial_approximation.on_disk(dop, ini, path, rad, eps)

Compute a polynomial approximation of a solution of dop on a complex disk.

EXAMPLES:

sage: from ore_algebra import *
sage: from ore_algebra.analytic import polynomial_approximation as polapprox
sage: QQi.<i> = QuadraticField(-1, 'I')
sage: Dops, x, Dx = DifferentialOperators()

sage: polapprox.on_disk(Dx - 1, [1], [0], 1, 1e-3)
([0.001...])*x^6 + ([0.008...])*x^5 + ([0.041...])*x^4
+ ([0.16...])*x^3 + 0.50...*x^2 + x + [1.00...] + [+/- ...]*I

TESTS:

sage: from ore_algebra.analytic.polynomial_approximation import _test_fun_approx
sage: pol = polapprox.on_disk(Dx - 1, [1], [0, i], 1, 1e-20)
sage: _test_fun_approx(pol, lambda b: (i + b).exp(), disk_rad=1, prec=200)
sage: pol = polapprox.on_disk(Dx^2 + 2*x*Dx, [0, 2/sqrt(RBF(pi))], [0], 2, 1e-10)
sage: _test_fun_approx(pol, lambda x: x.erf(), disk_rad=1)
sage: pol[0].abs() < RBF(10)^-10
True

Ensure that the polynomial we computed correctly takes into account that x may be complex, even though the Taylor series it is based on has real coefficients:

sage: pol.parent()
Univariate Polynomial Ring in x over Complex ball field with ... precision
sage: pol[0].imag().is_zero()
False
ore_algebra.analytic.polynomial_approximation.on_interval(dop, ini, path, eps, rad=None)

Compute a polynomial approximation of a solution of dop on a segment.

EXAMPLES:

sage: from ore_algebra import *
sage: from ore_algebra.analytic import polynomial_approximation as polapprox
sage: Dops, x, Dx = DifferentialOperators()

sage: pol1 = polapprox.on_interval(Dx - 1, [1], [0], 1e-3, rad=1); pol1
[0.008...]*x^5 + [0.04...]*x^4 + [0.166...]*x^3 + [0.499...]*x^2
+ [1.0...]*x + [1.0...]

sage: pol2 = polapprox.on_interval(Dx - 1, [1], [0, [1, 2]], 1e-3); pol2
[0.189...]*x^4 + [0.7...]*x^3 + [2.24...]*x^2 + [4.4...]*x + [4.4...]

TESTS:

sage: from ore_algebra.analytic.polynomial_approximation import _test_fun_approx
sage: _test_fun_approx(pol1, lambda b: b.exp(), interval_rad=1)
sage: _test_fun_approx(pol2, lambda b: (3/2 + b).exp(), interval_rad=.5)
sage: polapprox.on_interval(Dx - 1, [1], [0, [1, 2]], 1e-3, rad=1)
Traceback (most recent call last):
...
TypeError: unexpected value for point: [1, 2]
sage: polapprox.on_interval(Dx - 1, [1], [0], 1e-3)
Traceback (most recent call last):
...
TypeError: missing radius

sage: pol = polapprox.on_interval(Dx^2 - x,
....:         ini=[1/(gamma(2/3)*3^(2/3)), -1/(gamma(1/3)*3^(1/3))],
....:         path=[0,[-1,1]], eps=1e-8)
sage: _test_fun_approx(pol, lambda x: RBF(CBF(x).airy_ai()), interval_rad=1)
ore_algebra.analytic.polynomial_approximation.taylor_economization(pol, eps)

Economize a polynomial by removing monomials.

Remove terms from the polynomial pol, starting with the high-order terms, in such a way that its value on the disk |z| < 1 changes at most by eps.

A bound on the difference between the result and the input polynomial is added to the constant term, so that, for any complex number z with |z| < 1, the value of the result at z contains that of pol.

EXAMPLES:

sage: from ore_algebra.analytic.polynomial_approximation import taylor_economization
sage: pol = polygen(QQ, 'x')._exp_series(10).change_ring(RBF); pol
[2.755...e-6 +/- 5.96e-22]*x^9 + [2.480...e-5 +/- 4.96e-21]*x^8
+ [0.0001... +/- 3.97e-20]*x^7 + [0.0013... +/- 4.92e-19]*x^6 + ... +
x + 1.000000000000000
sage: newpol = taylor_economization(pol, RBF(1e-3)); newpol
([0.0013... +/- 4.92e-19])*x^6 + ... + x +
[1.000 +/- 2.26e-4] + [+/- 2.26e-4]*I

TESTS:

sage: from ore_algebra.analytic.polynomial_approximation import _test_fun_approx
sage: _test_fun_approx(newpol, pol, disk_rad=1)

sage: Pols.<x> = RBF[]
sage: taylor_economization(x^5 + 10*x^4 + x^3 + 2*x + 10, RBF(3))
10.0000...*x^4 + 2.0000...*x + [1e+1 +/- 2.01] + [+/- 2.01]*I