Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 r""" Univariate polynomials over `\CC` with interval coefficients using Arb.
This is a binding to the `Arb library <http://fredrikj.net/arb/>`_; it may be useful to refer to its documentation for more details.
Parts of the documentation for this module are copied or adapted from Arb's own documentation, licenced under the GNU General Public License version 2, or later.
.. SEEALSO::
- :mod:`Complex balls using Arb <sage.rings.complex_arb>`
TESTS:
sage: type(polygen(ComplexBallField(140))) <type 'sage.rings.polynomial.polynomial_complex_arb.Polynomial_complex_arb'> sage: Pol.<x> = CBF[] sage: (x+1/2)^3 x^3 + 1.500000000000000*x^2 + 0.7500000000000000*x + 0.1250000000000000
"""
from cysignals.signals cimport sig_on, sig_off
from sage.libs.arb.acb cimport * from sage.rings.integer cimport Integer, smallInteger from sage.rings.complex_arb cimport ComplexBall from sage.structure.element cimport Element
cdef inline long prec(Polynomial_complex_arb pol):
cdef class Polynomial_complex_arb(Polynomial): r""" Wrapper for `Arb <http://fredrikj.net/arb/>`_ polynomials of type ``acb_poly_t``
EXAMPLES::
sage: Pol.<x> = CBF[] sage: type(x) <type 'sage.rings.polynomial.polynomial_complex_arb.Polynomial_complex_arb'>
sage: Pol(), Pol(1), Pol([0,1,2]), Pol({1: pi, 3: i}) (0, 1.000000000000000, 2.000000000000000*x^2 + x, I*x^3 + ([3.141592653589793 +/- 5.61e-16])*x)
sage: Pol("x - 2/3") x + [-0.666666666666667 +/- 4.82e-16] sage: Pol(polygen(QQ)) x
sage: [Pol.has_coerce_map_from(P) for P in ....: QQ['x'], QuadraticField(-1), RealBallField(100)] [True, True, True] sage: [Pol.has_coerce_map_from(P) for P in ....: QQ['y'], RR, CC, RDF, CDF, RIF, CIF, RealBallField(20)] [False, False, False, False, False, False, False, False] """
# Memory management and initialization
def __cinit__(self): r""" TESTS::
sage: ComplexBallField(2)['y']() 0 """
def __dealloc__(self): r""" TESTS::
sage: pol = CBF['x']() sage: del pol """
cdef Polynomial_complex_arb _new(self): r""" Return a new polynomial with the same parent as this one. """
def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): r""" Initialize this polynomial to the specified value.
TESTS::
sage: from sage.rings.polynomial.polynomial_complex_arb import Polynomial_complex_arb sage: Pol = CBF['x'] sage: Polynomial_complex_arb(Pol) 0 sage: Polynomial_complex_arb(Pol, is_gen=True) x sage: Polynomial_complex_arb(Pol, 42, is_gen=True) x sage: Polynomial_complex_arb(Pol, CBF(1)) 1.000000000000000 sage: Polynomial_complex_arb(Pol, []) 0 sage: Polynomial_complex_arb(Pol, [0]) 0 sage: Polynomial_complex_arb(Pol, [0, 2, 0]) 2.000000000000000*x sage: Polynomial_complex_arb(Pol, (1,)) 1.000000000000000 sage: Polynomial_complex_arb(Pol, (CBF(i), 1)) x + I sage: Polynomial_complex_arb(Pol, polygen(QQ,'y')+2) x + 2.000000000000000 sage: Polynomial_complex_arb(Pol, QQ['x'](0)) 0 sage: Polynomial_complex_arb(Pol, {10: pi}) ([3.141592653589793 +/- 5.61e-16])*x^10 sage: Polynomial_complex_arb(Pol, pi) [3.141592653589793 +/- 5.61e-16] """ cdef ComplexBall ball cdef Polynomial pol cdef list lst cdef tuple tpl cdef dict dct cdef long length, i
acb_poly_set(self.__poly, (<Polynomial_complex_arb> x).__poly) else: acb_poly_zero(self.__poly) else: else:
# Access
def degree(self): r""" Return the (apparent) degree of this polynomial.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (x^2 + 1).degree() 2 sage: pol = (x/3 + 1) - x/3; pol ([+/- 1.12e-16])*x + 1.000000000000000 sage: pol.degree() 1 sage: Pol([1, 0, 0, 0]).degree() 0 """
cdef get_unsafe(self, Py_ssize_t n):
cpdef list list(self, bint copy=True): r""" Return the coefficient list of this polynomial.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (x^2/3).list() [0, 0, [0.3333333333333333 +/- 7.04e-17]] sage: Pol(0).list() [] sage: Pol([0, 1, RBF(0, rad=.1), 0]).list() [0, 1.000000000000000, [+/- 0.101]] """
def __nonzero__(self): r""" Return ``False`` if this polynomial is exactly zero, ``True`` otherwise.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: bool(Pol(0)) False sage: z = Pol(1/3) - 1/3 sage: bool(z) True """
# Ring and Euclidean arithmetic
cpdef _add_(self, other): r""" Return the sum of two polynomials.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (x + 1) + (x/3 - 2) ([1.333333333333333 +/- 5.37e-16])*x - 1.000000000000000 """ res.__poly, self.__poly, (<Polynomial_complex_arb> other).__poly, prec(self))
cpdef _neg_(self): r""" Return the opposite of this polynomial.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: -(x/3 - 2) ([-0.3333333333333333 +/- 7.04e-17])*x + 2.000000000000000 """
cpdef _sub_(self, other): r""" Return the difference of two polynomials.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (x + 1) - (x/3 - 2) ([0.666666666666667 +/- 5.37e-16])*x + 3.000000000000000 """ res.__poly, self.__poly, (<Polynomial_complex_arb> other).__poly, prec(self))
cpdef _mul_(self, other): r""" Return the product of two polynomials.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (x + 1)*(x/3 - 2) ([0.3333333333333333 +/- 7.04e-17])*x^2 + ([-1.666666666666667 +/- 7.59e-16])*x - 2.000000000000000 """ res.__poly, self.__poly, (<Polynomial_complex_arb> other).__poly, prec(self))
cpdef _lmul_(self, Element a): r""" TESTS::
sage: Pol.<x> = CBF[] sage: (x + 1)._lmul_(CBF(3)) 3.000000000000000*x + 3.000000000000000 sage: (1 + x)*(1/3) ([0.3333333333333333 +/- 7.04e-17])*x + [0.3333333333333333 +/- 7.04e-17] sage: (1 + x)*GF(2)(1) Traceback (most recent call last): ... TypeError: unsupported operand parent(s)... """
cpdef _rmul_(self, Element a): r""" TESTS::
sage: Pol.<x> = CBF[] sage: (x + 1)._rmul_(CBF(3)) 3.000000000000000*x + 3.000000000000000 sage: (1/3)*(1 + x) ([0.3333333333333333 +/- 7.04e-17])*x + [0.3333333333333333 +/- 7.04e-17] """
r""" Compute the Euclidean division of this ball polynomial by ``divisor``.
Raises a ``ZeroDivisionError`` when the divisor is zero or its leading coefficient contains zero. Returns a pair (quotient, remainder) otherwise.
EXAMPLES::
sage: Pol.<x> = CBF[]
sage: (x^3/7 - CBF(i)).quo_rem(x + CBF(pi)) (([0.1428571428571428 +/- 7.70e-17])*x^2 + ([-0.448798950512828 +/- 6.74e-16])*x + [1.40994348586991 +/- 3.04e-15], [-4.42946809718569 +/- 7.86e-15] - I)
sage: Pol(0).quo_rem(x + 1) (0, 0)
sage: (x + 1).quo_rem(0) Traceback (most recent call last): ... ZeroDivisionError: ('cannot divide by this polynomial', 0)
sage: div = (x^2/3 + x + 1) - x^2/3; div ([+/- 1.12e-16])*x^2 + x + 1.000000000000000 sage: (x + 1).quo_rem(div) Traceback (most recent call last): ... ZeroDivisionError: ('cannot divide by this polynomial', ([+/- 1.12e-16])*x^2 + x + 1.000000000000000) """ div.__poly, prec(self)) else:
# Syntactic transformations
cpdef Polynomial truncate(self, long n): r""" Return the truncation to degree `n - 1` of this polynomial.
EXAMPLES::
sage: pol = CBF['x'](range(1,5)); pol 4.000000000000000*x^3 + 3.000000000000000*x^2 + 2.000000000000000*x + 1.000000000000000 sage: pol.truncate(2) 2.000000000000000*x + 1.000000000000000 sage: pol.truncate(0) 0 sage: pol.truncate(-1) 0
TESTS::
sage: pol.truncate(6) 4.000000000000000*x^3 + 3.000000000000000*x^2 + 2.000000000000000*x + 1.000000000000000 sage: pol.truncate(4) 4.000000000000000*x^3 + 3.000000000000000*x^2 + 2.000000000000000*x + 1.000000000000000 """
cdef _inplace_truncate(self, long n): if n < 0: n = 0 acb_poly_truncate(self.__poly, n) return self
def __lshift__(val, n): r""" Shift ``val`` to the left, i.e. multiply it by `x^n`, throwing away coefficients if `n < 0`.
EXAMPLES::
sage: pol = CBF['x'](range(1,5)); pol 4.000000000000000*x^3 + 3.000000000000000*x^2 + 2.000000000000000*x + 1.000000000000000 sage: pol << 2 4.000000000000000*x^5 + 3.000000000000000*x^4 + 2.000000000000000*x^3 + x^2 sage: pol << (-2) 4.000000000000000*x + 3.000000000000000
TESTS::
sage: 1 << pol Traceback (most recent call last): ... TypeError: unsupported operands for <<: 1, 4.000000000000000*x^3 + 3.000000000000000*x^2 + 2.000000000000000*x + 1.000000000000000 """ raise TypeError("unsupported operand type(s) for <<: '{}' and '{}'" .format(type(val).__name__, type(n).__name__))
def __rshift__(val, n): r""" Shift ``val`` to the left, i.e. divide it by `x^n`, throwing away coefficients if `n > 0`.
EXAMPLES::
sage: pol = CBF['x'](range(1,5)); pol 4.000000000000000*x^3 + 3.000000000000000*x^2 + 2.000000000000000*x + 1.000000000000000 sage: pol >> 2 4.000000000000000*x + 3.000000000000000 sage: pol >> -2 4.000000000000000*x^5 + 3.000000000000000*x^4 + 2.000000000000000*x^3 + x^2
TESTS::
sage: 1 >> pol Traceback (most recent call last): ... TypeError: unsupported operands for >>: 1, 4.000000000000000*x^3 + 3.000000000000000*x^2 + 2.000000000000000*x + 1.000000000000000 """ raise TypeError("unsupported operand type(s) for <<: '{}' and '{}'" .format(type(val).__name__, type(n).__name__))
# Truncated and power series arithmetic
cpdef Polynomial _mul_trunc_(self, Polynomial other, long n): r""" Return the product of ``self`` and ``other``, truncated before degree `n`.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (x + 1)._mul_trunc_(x + 2, 2) 3.000000000000000*x + 2.000000000000000 sage: (x + 1)._mul_trunc_(x + 2, 0) 0 sage: (x + 1)._mul_trunc_(x + 2, -1) 0
TESTS::
sage: (x + 1)._mul_trunc_(x + 2, 4) x^2 + 3.000000000000000*x + 2.000000000000000 """
cpdef Polynomial inverse_series_trunc(self, long n): r""" Return the power series expansion at 0 of the inverse of this polynomial, truncated before degree `n`.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (1 - x/3).inverse_series_trunc(3) ([0.1111111111111111 +/- 5.99e-17])*x^2 + ([0.3333333333333333 +/- 7.04e-17])*x + 1.000000000000000 sage: x.inverse_series_trunc(1) [+/- inf] sage: Pol(0).inverse_series_trunc(2) (nan + nan*I)*x + nan + nan*I
TESTS::
sage: Pol(0).inverse_series_trunc(-1) 0 """
cpdef Polynomial _power_trunc(self, unsigned long expo, long n): r""" Return a power of this polynomial, truncated before degree `n`.
INPUT:
- ``expo`` - non-negative integer exponent - ``n`` - truncation order
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (x^2 + 1)._power_trunc(10^9, 3) 1000000000.000000*x^2 + 1.000000000000000 sage: (x^2 + 1)._power_trunc(10^20, 0) Traceback (most recent call last): ... OverflowError: ... int too large to convert...
TESTS::
sage: (x^2 + 1)._power_trunc(10, -3) 0 sage: (x^2 + 1)._power_trunc(-1, 0) Traceback (most recent call last): ... OverflowError: can't convert negative value to unsigned long """
def _log_series(self, long n): r""" Return the power series expansion at 0 of the logarithm of this polynomial, truncated before degree `n`.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (1 + x/3)._log_series(3) ([-0.0555555555555555 +/- 7.10e-17])*x^2 + ([0.3333333333333333 +/- 7.04e-17])*x sage: (-1 + x)._log_series(3) -0.5000000000000000*x^2 - x + [3.141592653589793 +/- 5.61e-16]*I
An example where the constant term crosses the branch cut of the logarithm::
sage: pol = CBF(-1, RBF(0, rad=.01)) + x; pol x - 1.000000000000000 + [+/- 0.0101]*I sage: pol._log_series(2) ([-1.000 +/- 1.01e-4] + [+/- 0.0101]*I)*x + [+/- 5.01e-5] + [+/- 3.15]*I
Some cases where the result is not defined::
sage: x._log_series(1) nan + nan*I sage: Pol(0)._log_series(1) nan + nan*I """ n = 0
def _exp_series(self, long n): r""" Return the power series expansion at 0 of the exponential of this polynomial, truncated before degree `n`.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: x._exp_series(3) 0.5000000000000000*x^2 + x + 1.000000000000000 sage: (1 + x/3)._log_series(3)._exp_series(3) ([+/- 5.09e-17])*x^2 + ([0.3333333333333333 +/- 7.04e-17])*x + 1.000000000000000 sage: (CBF(0, pi) + x)._exp_series(4) ([-0.166...] + [+/- ...]*I)*x^3 + ([-0.500...] + [+/- ...]*I)*x^2 + ([-1.000...] + [+/- ...]*I)*x + [-1.000...] + [+/- ...]*I """ n = 0
def _sqrt_series(self, long n): r""" Return the power series expansion at 0 of the square root of this polynomial, truncated before degree `n`.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: (1 + x)._sqrt_series(3) -0.1250000000000000*x^2 + 0.5000000000000000*x + 1.000000000000000 sage: pol = CBF(-1, RBF(0, rad=.01)) + x; pol x - 1.000000000000000 + [+/- 0.0101]*I sage: pol._sqrt_series(2) ([+/- 7.51e-3] + [+/- 0.501]*I)*x + [+/- 5.01e-3] + [+/- 1.01]*I sage: x._sqrt_series(2) ([+/- inf] + [+/- inf]*I)*x """ n = 0
def compose_trunc(self, Polynomial other, long n): r""" Return the composition of ``self`` and ``other``, truncated before degree `n`.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: Pol.<x> = CBF[] sage: pol = x*(x-1)^2 sage: pol.compose_trunc(x + x^2, 4) -3.000000000000000*x^3 - x^2 + x sage: pol.compose_trunc(1 + x, 4) x^3 + x^2 sage: pol.compose_trunc(2 + x/3, 2) ([1.666666666666667 +/- 9.81e-16])*x + 2.000000000000000 sage: pol.compose_trunc(2 + x/3, 0) 0 sage: pol.compose_trunc(2 + x/3, -1) 0 """ return self(other).truncate(n) cdef acb_poly_t self_ts, other_ts cdef acb_ptr cc finally:
def revert_series(self, long n): r""" Return a polynomial ``f`` such that ``f(self(x)) = self(f(x)) = x mod x^n``.
EXAMPLES::
sage: Pol.<x> = CBF[]
sage: (2*x).revert_series(5) 0.5000000000000000*x
sage: (x + x^3/6 + x^5/120).revert_series(6) ([0.075000000000000 +/- 9.75e-17])*x^5 + ([-0.166666666666667 +/- 4.45e-16])*x^3 + x
sage: (1 + x).revert_series(6) Traceback (most recent call last): ... ValueError: the constant coefficient must be zero
sage: (x^2).revert_series(6) Traceback (most recent call last): ... ValueError: the linear term must be nonzero """ n = 0
# Evaluation
def __call__(self, *x, **kwds): r""" Evaluate this polynomial.
EXAMPLES::
sage: Pol.<x> = CBF[] sage: pol = x^2 - 1 sage: pol(CBF(pi)) [8.86960440108936 +/- 8.36e-15] sage: pol(x^3 + 1) x^6 + 2.000000000000000*x^3 sage: pol(matrix([[1,2],[3,4]])) [6.000000000000000 10.00000000000000] [15.00000000000000 21.00000000000000] """ cdef ComplexBall ball cdef Polynomial_complex_arb poly # parent of result = base ring of self (not parent of point) (<ComplexBall> point).value, prec(self)) (<Polynomial_complex_arb> point).__poly, prec(self)) # TODO: perhaps add more special cases, e.g. for real ball, # integers and rationals |