1466 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1466 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""
 | 
						|
Functions to operate on polynomials.
 | 
						|
 | 
						|
"""
 | 
						|
__all__ = ['poly', 'roots', 'polyint', 'polyder', 'polyadd',
 | 
						|
           'polysub', 'polymul', 'polydiv', 'polyval', 'poly1d',
 | 
						|
           'polyfit']
 | 
						|
 | 
						|
import functools
 | 
						|
import re
 | 
						|
import warnings
 | 
						|
 | 
						|
import numpy._core.numeric as NX
 | 
						|
from numpy._core import (
 | 
						|
    abs,
 | 
						|
    array,
 | 
						|
    atleast_1d,
 | 
						|
    dot,
 | 
						|
    finfo,
 | 
						|
    hstack,
 | 
						|
    isscalar,
 | 
						|
    ones,
 | 
						|
    overrides,
 | 
						|
)
 | 
						|
from numpy._utils import set_module
 | 
						|
from numpy.exceptions import RankWarning
 | 
						|
from numpy.lib._function_base_impl import trim_zeros
 | 
						|
from numpy.lib._twodim_base_impl import diag, vander
 | 
						|
from numpy.lib._type_check_impl import imag, iscomplex, mintypecode, real
 | 
						|
from numpy.linalg import eigvals, inv, lstsq
 | 
						|
 | 
						|
array_function_dispatch = functools.partial(
 | 
						|
    overrides.array_function_dispatch, module='numpy')
 | 
						|
 | 
						|
 | 
						|
def _poly_dispatcher(seq_of_zeros):
 | 
						|
    return seq_of_zeros
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_poly_dispatcher)
 | 
						|
def poly(seq_of_zeros):
 | 
						|
    """
 | 
						|
    Find the coefficients of a polynomial with the given sequence of roots.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    Returns the coefficients of the polynomial whose leading coefficient
 | 
						|
    is one for the given sequence of zeros (multiple roots must be included
 | 
						|
    in the sequence as many times as their multiplicity; see Examples).
 | 
						|
    A square matrix (or array, which will be treated as a matrix) can also
 | 
						|
    be given, in which case the coefficients of the characteristic polynomial
 | 
						|
    of the matrix are returned.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    seq_of_zeros : array_like, shape (N,) or (N, N)
 | 
						|
        A sequence of polynomial roots, or a square array or matrix object.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    c : ndarray
 | 
						|
        1D array of polynomial coefficients from highest to lowest degree:
 | 
						|
 | 
						|
        ``c[0] * x**(N) + c[1] * x**(N-1) + ... + c[N-1] * x + c[N]``
 | 
						|
        where c[0] always equals 1.
 | 
						|
 | 
						|
    Raises
 | 
						|
    ------
 | 
						|
    ValueError
 | 
						|
        If input is the wrong shape (the input must be a 1-D or square
 | 
						|
        2-D array).
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    polyval : Compute polynomial values.
 | 
						|
    roots : Return the roots of a polynomial.
 | 
						|
    polyfit : Least squares polynomial fit.
 | 
						|
    poly1d : A one-dimensional polynomial class.
 | 
						|
 | 
						|
    Notes
 | 
						|
    -----
 | 
						|
    Specifying the roots of a polynomial still leaves one degree of
 | 
						|
    freedom, typically represented by an undetermined leading
 | 
						|
    coefficient. [1]_ In the case of this function, that coefficient -
 | 
						|
    the first one in the returned array - is always taken as one. (If
 | 
						|
    for some reason you have one other point, the only automatic way
 | 
						|
    presently to leverage that information is to use ``polyfit``.)
 | 
						|
 | 
						|
    The characteristic polynomial, :math:`p_a(t)`, of an `n`-by-`n`
 | 
						|
    matrix **A** is given by
 | 
						|
 | 
						|
    :math:`p_a(t) = \\mathrm{det}(t\\, \\mathbf{I} - \\mathbf{A})`,
 | 
						|
 | 
						|
    where **I** is the `n`-by-`n` identity matrix. [2]_
 | 
						|
 | 
						|
    References
 | 
						|
    ----------
 | 
						|
    .. [1] M. Sullivan and M. Sullivan, III, "Algebra and Trigonometry,
 | 
						|
       Enhanced With Graphing Utilities," Prentice-Hall, pg. 318, 1996.
 | 
						|
 | 
						|
    .. [2] G. Strang, "Linear Algebra and Its Applications, 2nd Edition,"
 | 
						|
       Academic Press, pg. 182, 1980.
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
 | 
						|
    Given a sequence of a polynomial's zeros:
 | 
						|
 | 
						|
    >>> import numpy as np
 | 
						|
 | 
						|
    >>> np.poly((0, 0, 0)) # Multiple root example
 | 
						|
    array([1., 0., 0., 0.])
 | 
						|
 | 
						|
    The line above represents z**3 + 0*z**2 + 0*z + 0.
 | 
						|
 | 
						|
    >>> np.poly((-1./2, 0, 1./2))
 | 
						|
    array([ 1.  ,  0.  , -0.25,  0.  ])
 | 
						|
 | 
						|
    The line above represents z**3 - z/4
 | 
						|
 | 
						|
    >>> np.poly((np.random.random(1)[0], 0, np.random.random(1)[0]))
 | 
						|
    array([ 1.        , -0.77086955,  0.08618131,  0.        ]) # random
 | 
						|
 | 
						|
    Given a square array object:
 | 
						|
 | 
						|
    >>> P = np.array([[0, 1./3], [-1./2, 0]])
 | 
						|
    >>> np.poly(P)
 | 
						|
    array([1.        , 0.        , 0.16666667])
 | 
						|
 | 
						|
    Note how in all cases the leading coefficient is always 1.
 | 
						|
 | 
						|
    """
 | 
						|
    seq_of_zeros = atleast_1d(seq_of_zeros)
 | 
						|
    sh = seq_of_zeros.shape
 | 
						|
 | 
						|
    if len(sh) == 2 and sh[0] == sh[1] and sh[0] != 0:
 | 
						|
        seq_of_zeros = eigvals(seq_of_zeros)
 | 
						|
    elif len(sh) == 1:
 | 
						|
        dt = seq_of_zeros.dtype
 | 
						|
        # Let object arrays slip through, e.g. for arbitrary precision
 | 
						|
        if dt != object:
 | 
						|
            seq_of_zeros = seq_of_zeros.astype(mintypecode(dt.char))
 | 
						|
    else:
 | 
						|
        raise ValueError("input must be 1d or non-empty square 2d array.")
 | 
						|
 | 
						|
    if len(seq_of_zeros) == 0:
 | 
						|
        return 1.0
 | 
						|
    dt = seq_of_zeros.dtype
 | 
						|
    a = ones((1,), dtype=dt)
 | 
						|
    for zero in seq_of_zeros:
 | 
						|
        a = NX.convolve(a, array([1, -zero], dtype=dt), mode='full')
 | 
						|
 | 
						|
    if issubclass(a.dtype.type, NX.complexfloating):
 | 
						|
        # if complex roots are all complex conjugates, the roots are real.
 | 
						|
        roots = NX.asarray(seq_of_zeros, complex)
 | 
						|
        if NX.all(NX.sort(roots) == NX.sort(roots.conjugate())):
 | 
						|
            a = a.real.copy()
 | 
						|
 | 
						|
    return a
 | 
						|
 | 
						|
 | 
						|
def _roots_dispatcher(p):
 | 
						|
    return p
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_roots_dispatcher)
 | 
						|
def roots(p):
 | 
						|
    """
 | 
						|
    Return the roots of a polynomial with coefficients given in p.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    The values in the rank-1 array `p` are coefficients of a polynomial.
 | 
						|
    If the length of `p` is n+1 then the polynomial is described by::
 | 
						|
 | 
						|
      p[0] * x**n + p[1] * x**(n-1) + ... + p[n-1]*x + p[n]
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    p : array_like
 | 
						|
        Rank-1 array of polynomial coefficients.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    out : ndarray
 | 
						|
        An array containing the roots of the polynomial.
 | 
						|
 | 
						|
    Raises
 | 
						|
    ------
 | 
						|
    ValueError
 | 
						|
        When `p` cannot be converted to a rank-1 array.
 | 
						|
 | 
						|
    See also
 | 
						|
    --------
 | 
						|
    poly : Find the coefficients of a polynomial with a given sequence
 | 
						|
           of roots.
 | 
						|
    polyval : Compute polynomial values.
 | 
						|
    polyfit : Least squares polynomial fit.
 | 
						|
    poly1d : A one-dimensional polynomial class.
 | 
						|
 | 
						|
    Notes
 | 
						|
    -----
 | 
						|
    The algorithm relies on computing the eigenvalues of the
 | 
						|
    companion matrix [1]_.
 | 
						|
 | 
						|
    References
 | 
						|
    ----------
 | 
						|
    .. [1] R. A. Horn & C. R. Johnson, *Matrix Analysis*.  Cambridge, UK:
 | 
						|
        Cambridge University Press, 1999, pp. 146-7.
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> import numpy as np
 | 
						|
    >>> coeff = [3.2, 2, 1]
 | 
						|
    >>> np.roots(coeff)
 | 
						|
    array([-0.3125+0.46351241j, -0.3125-0.46351241j])
 | 
						|
 | 
						|
    """
 | 
						|
    # If input is scalar, this makes it an array
 | 
						|
    p = atleast_1d(p)
 | 
						|
    if p.ndim != 1:
 | 
						|
        raise ValueError("Input must be a rank-1 array.")
 | 
						|
 | 
						|
    # find non-zero array entries
 | 
						|
    non_zero = NX.nonzero(NX.ravel(p))[0]
 | 
						|
 | 
						|
    # Return an empty array if polynomial is all zeros
 | 
						|
    if len(non_zero) == 0:
 | 
						|
        return NX.array([])
 | 
						|
 | 
						|
    # find the number of trailing zeros -- this is the number of roots at 0.
 | 
						|
    trailing_zeros = len(p) - non_zero[-1] - 1
 | 
						|
 | 
						|
    # strip leading and trailing zeros
 | 
						|
    p = p[int(non_zero[0]):int(non_zero[-1]) + 1]
 | 
						|
 | 
						|
    # casting: if incoming array isn't floating point, make it floating point.
 | 
						|
    if not issubclass(p.dtype.type, (NX.floating, NX.complexfloating)):
 | 
						|
        p = p.astype(float)
 | 
						|
 | 
						|
    N = len(p)
 | 
						|
    if N > 1:
 | 
						|
        # build companion matrix and find its eigenvalues (the roots)
 | 
						|
        A = diag(NX.ones((N - 2,), p.dtype), -1)
 | 
						|
        A[0, :] = -p[1:] / p[0]
 | 
						|
        roots = eigvals(A)
 | 
						|
    else:
 | 
						|
        roots = NX.array([])
 | 
						|
 | 
						|
    # tack any zeros onto the back of the array
 | 
						|
    roots = hstack((roots, NX.zeros(trailing_zeros, roots.dtype)))
 | 
						|
    return roots
 | 
						|
 | 
						|
 | 
						|
def _polyint_dispatcher(p, m=None, k=None):
 | 
						|
    return (p,)
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_polyint_dispatcher)
 | 
						|
def polyint(p, m=1, k=None):
 | 
						|
    """
 | 
						|
    Return an antiderivative (indefinite integral) of a polynomial.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    The returned order `m` antiderivative `P` of polynomial `p` satisfies
 | 
						|
    :math:`\\frac{d^m}{dx^m}P(x) = p(x)` and is defined up to `m - 1`
 | 
						|
    integration constants `k`. The constants determine the low-order
 | 
						|
    polynomial part
 | 
						|
 | 
						|
    .. math:: \\frac{k_{m-1}}{0!} x^0 + \\ldots + \\frac{k_0}{(m-1)!}x^{m-1}
 | 
						|
 | 
						|
    of `P` so that :math:`P^{(j)}(0) = k_{m-j-1}`.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    p : array_like or poly1d
 | 
						|
        Polynomial to integrate.
 | 
						|
        A sequence is interpreted as polynomial coefficients, see `poly1d`.
 | 
						|
    m : int, optional
 | 
						|
        Order of the antiderivative. (Default: 1)
 | 
						|
    k : list of `m` scalars or scalar, optional
 | 
						|
        Integration constants. They are given in the order of integration:
 | 
						|
        those corresponding to highest-order terms come first.
 | 
						|
 | 
						|
        If ``None`` (default), all constants are assumed to be zero.
 | 
						|
        If `m = 1`, a single scalar can be given instead of a list.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    polyder : derivative of a polynomial
 | 
						|
    poly1d.integ : equivalent method
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
 | 
						|
    The defining property of the antiderivative:
 | 
						|
 | 
						|
    >>> import numpy as np
 | 
						|
 | 
						|
    >>> p = np.poly1d([1,1,1])
 | 
						|
    >>> P = np.polyint(p)
 | 
						|
    >>> P
 | 
						|
     poly1d([ 0.33333333,  0.5       ,  1.        ,  0.        ]) # may vary
 | 
						|
    >>> np.polyder(P) == p
 | 
						|
    True
 | 
						|
 | 
						|
    The integration constants default to zero, but can be specified:
 | 
						|
 | 
						|
    >>> P = np.polyint(p, 3)
 | 
						|
    >>> P(0)
 | 
						|
    0.0
 | 
						|
    >>> np.polyder(P)(0)
 | 
						|
    0.0
 | 
						|
    >>> np.polyder(P, 2)(0)
 | 
						|
    0.0
 | 
						|
    >>> P = np.polyint(p, 3, k=[6,5,3])
 | 
						|
    >>> P
 | 
						|
    poly1d([ 0.01666667,  0.04166667,  0.16666667,  3. ,  5. ,  3. ]) # may vary
 | 
						|
 | 
						|
    Note that 3 = 6 / 2!, and that the constants are given in the order of
 | 
						|
    integrations. Constant of the highest-order polynomial term comes first:
 | 
						|
 | 
						|
    >>> np.polyder(P, 2)(0)
 | 
						|
    6.0
 | 
						|
    >>> np.polyder(P, 1)(0)
 | 
						|
    5.0
 | 
						|
    >>> P(0)
 | 
						|
    3.0
 | 
						|
 | 
						|
    """
 | 
						|
    m = int(m)
 | 
						|
    if m < 0:
 | 
						|
        raise ValueError("Order of integral must be positive (see polyder)")
 | 
						|
    if k is None:
 | 
						|
        k = NX.zeros(m, float)
 | 
						|
    k = atleast_1d(k)
 | 
						|
    if len(k) == 1 and m > 1:
 | 
						|
        k = k[0] * NX.ones(m, float)
 | 
						|
    if len(k) < m:
 | 
						|
        raise ValueError(
 | 
						|
              "k must be a scalar or a rank-1 array of length 1 or >m.")
 | 
						|
 | 
						|
    truepoly = isinstance(p, poly1d)
 | 
						|
    p = NX.asarray(p)
 | 
						|
    if m == 0:
 | 
						|
        if truepoly:
 | 
						|
            return poly1d(p)
 | 
						|
        return p
 | 
						|
    else:
 | 
						|
        # Note: this must work also with object and integer arrays
 | 
						|
        y = NX.concatenate((p.__truediv__(NX.arange(len(p), 0, -1)), [k[0]]))
 | 
						|
        val = polyint(y, m - 1, k=k[1:])
 | 
						|
        if truepoly:
 | 
						|
            return poly1d(val)
 | 
						|
        return val
 | 
						|
 | 
						|
 | 
						|
def _polyder_dispatcher(p, m=None):
 | 
						|
    return (p,)
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_polyder_dispatcher)
 | 
						|
def polyder(p, m=1):
 | 
						|
    """
 | 
						|
    Return the derivative of the specified order of a polynomial.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    p : poly1d or sequence
 | 
						|
        Polynomial to differentiate.
 | 
						|
        A sequence is interpreted as polynomial coefficients, see `poly1d`.
 | 
						|
    m : int, optional
 | 
						|
        Order of differentiation (default: 1)
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    der : poly1d
 | 
						|
        A new polynomial representing the derivative.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    polyint : Anti-derivative of a polynomial.
 | 
						|
    poly1d : Class for one-dimensional polynomials.
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
 | 
						|
    The derivative of the polynomial :math:`x^3 + x^2 + x^1 + 1` is:
 | 
						|
 | 
						|
    >>> import numpy as np
 | 
						|
 | 
						|
    >>> p = np.poly1d([1,1,1,1])
 | 
						|
    >>> p2 = np.polyder(p)
 | 
						|
    >>> p2
 | 
						|
    poly1d([3, 2, 1])
 | 
						|
 | 
						|
    which evaluates to:
 | 
						|
 | 
						|
    >>> p2(2.)
 | 
						|
    17.0
 | 
						|
 | 
						|
    We can verify this, approximating the derivative with
 | 
						|
    ``(f(x + h) - f(x))/h``:
 | 
						|
 | 
						|
    >>> (p(2. + 0.001) - p(2.)) / 0.001
 | 
						|
    17.007000999997857
 | 
						|
 | 
						|
    The fourth-order derivative of a 3rd-order polynomial is zero:
 | 
						|
 | 
						|
    >>> np.polyder(p, 2)
 | 
						|
    poly1d([6, 2])
 | 
						|
    >>> np.polyder(p, 3)
 | 
						|
    poly1d([6])
 | 
						|
    >>> np.polyder(p, 4)
 | 
						|
    poly1d([0])
 | 
						|
 | 
						|
    """
 | 
						|
    m = int(m)
 | 
						|
    if m < 0:
 | 
						|
        raise ValueError("Order of derivative must be positive (see polyint)")
 | 
						|
 | 
						|
    truepoly = isinstance(p, poly1d)
 | 
						|
    p = NX.asarray(p)
 | 
						|
    n = len(p) - 1
 | 
						|
    y = p[:-1] * NX.arange(n, 0, -1)
 | 
						|
    if m == 0:
 | 
						|
        val = p
 | 
						|
    else:
 | 
						|
        val = polyder(y, m - 1)
 | 
						|
    if truepoly:
 | 
						|
        val = poly1d(val)
 | 
						|
    return val
 | 
						|
 | 
						|
 | 
						|
def _polyfit_dispatcher(x, y, deg, rcond=None, full=None, w=None, cov=None):
 | 
						|
    return (x, y, w)
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_polyfit_dispatcher)
 | 
						|
def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
 | 
						|
    """
 | 
						|
    Least squares polynomial fit.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    Fit a polynomial ``p(x) = p[0] * x**deg + ... + p[deg]`` of degree `deg`
 | 
						|
    to points `(x, y)`. Returns a vector of coefficients `p` that minimises
 | 
						|
    the squared error in the order `deg`, `deg-1`, ... `0`.
 | 
						|
 | 
						|
    The `Polynomial.fit <numpy.polynomial.polynomial.Polynomial.fit>` class
 | 
						|
    method is recommended for new code as it is more stable numerically. See
 | 
						|
    the documentation of the method for more information.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    x : array_like, shape (M,)
 | 
						|
        x-coordinates of the M sample points ``(x[i], y[i])``.
 | 
						|
    y : array_like, shape (M,) or (M, K)
 | 
						|
        y-coordinates of the sample points. Several data sets of sample
 | 
						|
        points sharing the same x-coordinates can be fitted at once by
 | 
						|
        passing in a 2D-array that contains one dataset per column.
 | 
						|
    deg : int
 | 
						|
        Degree of the fitting polynomial
 | 
						|
    rcond : float, optional
 | 
						|
        Relative condition number of the fit. Singular values smaller than
 | 
						|
        this relative to the largest singular value will be ignored. The
 | 
						|
        default value is len(x)*eps, where eps is the relative precision of
 | 
						|
        the float type, about 2e-16 in most cases.
 | 
						|
    full : bool, optional
 | 
						|
        Switch determining nature of return value. When it is False (the
 | 
						|
        default) just the coefficients are returned, when True diagnostic
 | 
						|
        information from the singular value decomposition is also returned.
 | 
						|
    w : array_like, shape (M,), optional
 | 
						|
        Weights. If not None, the weight ``w[i]`` applies to the unsquared
 | 
						|
        residual ``y[i] - y_hat[i]`` at ``x[i]``. Ideally the weights are
 | 
						|
        chosen so that the errors of the products ``w[i]*y[i]`` all have the
 | 
						|
        same variance.  When using inverse-variance weighting, use
 | 
						|
        ``w[i] = 1/sigma(y[i])``.  The default value is None.
 | 
						|
    cov : bool or str, optional
 | 
						|
        If given and not `False`, return not just the estimate but also its
 | 
						|
        covariance matrix. By default, the covariance are scaled by
 | 
						|
        chi2/dof, where dof = M - (deg + 1), i.e., the weights are presumed
 | 
						|
        to be unreliable except in a relative sense and everything is scaled
 | 
						|
        such that the reduced chi2 is unity. This scaling is omitted if
 | 
						|
        ``cov='unscaled'``, as is relevant for the case that the weights are
 | 
						|
        w = 1/sigma, with sigma known to be a reliable estimate of the
 | 
						|
        uncertainty.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    p : ndarray, shape (deg + 1,) or (deg + 1, K)
 | 
						|
        Polynomial coefficients, highest power first.  If `y` was 2-D, the
 | 
						|
        coefficients for `k`-th data set are in ``p[:,k]``.
 | 
						|
 | 
						|
    residuals, rank, singular_values, rcond
 | 
						|
        These values are only returned if ``full == True``
 | 
						|
 | 
						|
        - residuals -- sum of squared residuals of the least squares fit
 | 
						|
        - rank -- the effective rank of the scaled Vandermonde
 | 
						|
           coefficient matrix
 | 
						|
        - singular_values -- singular values of the scaled Vandermonde
 | 
						|
           coefficient matrix
 | 
						|
        - rcond -- value of `rcond`.
 | 
						|
 | 
						|
        For more details, see `numpy.linalg.lstsq`.
 | 
						|
 | 
						|
    V : ndarray, shape (deg + 1, deg + 1) or (deg + 1, deg + 1, K)
 | 
						|
        Present only if ``full == False`` and ``cov == True``.  The covariance
 | 
						|
        matrix of the polynomial coefficient estimates.  The diagonal of
 | 
						|
        this matrix are the variance estimates for each coefficient.  If y
 | 
						|
        is a 2-D array, then the covariance matrix for the `k`-th data set
 | 
						|
        are in ``V[:,:,k]``
 | 
						|
 | 
						|
 | 
						|
    Warns
 | 
						|
    -----
 | 
						|
    RankWarning
 | 
						|
        The rank of the coefficient matrix in the least-squares fit is
 | 
						|
        deficient. The warning is only raised if ``full == False``.
 | 
						|
 | 
						|
        The warnings can be turned off by
 | 
						|
 | 
						|
        >>> import warnings
 | 
						|
        >>> warnings.simplefilter('ignore', np.exceptions.RankWarning)
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    polyval : Compute polynomial values.
 | 
						|
    linalg.lstsq : Computes a least-squares fit.
 | 
						|
    scipy.interpolate.UnivariateSpline : Computes spline fits.
 | 
						|
 | 
						|
    Notes
 | 
						|
    -----
 | 
						|
    The solution minimizes the squared error
 | 
						|
 | 
						|
    .. math::
 | 
						|
        E = \\sum_{j=0}^k |p(x_j) - y_j|^2
 | 
						|
 | 
						|
    in the equations::
 | 
						|
 | 
						|
        x[0]**n * p[0] + ... + x[0] * p[n-1] + p[n] = y[0]
 | 
						|
        x[1]**n * p[0] + ... + x[1] * p[n-1] + p[n] = y[1]
 | 
						|
        ...
 | 
						|
        x[k]**n * p[0] + ... + x[k] * p[n-1] + p[n] = y[k]
 | 
						|
 | 
						|
    The coefficient matrix of the coefficients `p` is a Vandermonde matrix.
 | 
						|
 | 
						|
    `polyfit` issues a `~exceptions.RankWarning` when the least-squares fit is
 | 
						|
    badly conditioned. This implies that the best fit is not well-defined due
 | 
						|
    to numerical error. The results may be improved by lowering the polynomial
 | 
						|
    degree or by replacing `x` by `x` - `x`.mean(). The `rcond` parameter
 | 
						|
    can also be set to a value smaller than its default, but the resulting
 | 
						|
    fit may be spurious: including contributions from the small singular
 | 
						|
    values can add numerical noise to the result.
 | 
						|
 | 
						|
    Note that fitting polynomial coefficients is inherently badly conditioned
 | 
						|
    when the degree of the polynomial is large or the interval of sample points
 | 
						|
    is badly centered. The quality of the fit should always be checked in these
 | 
						|
    cases. When polynomial fits are not satisfactory, splines may be a good
 | 
						|
    alternative.
 | 
						|
 | 
						|
    References
 | 
						|
    ----------
 | 
						|
    .. [1] Wikipedia, "Curve fitting",
 | 
						|
           https://en.wikipedia.org/wiki/Curve_fitting
 | 
						|
    .. [2] Wikipedia, "Polynomial interpolation",
 | 
						|
           https://en.wikipedia.org/wiki/Polynomial_interpolation
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> import numpy as np
 | 
						|
    >>> import warnings
 | 
						|
    >>> x = np.array([0.0, 1.0, 2.0, 3.0,  4.0,  5.0])
 | 
						|
    >>> y = np.array([0.0, 0.8, 0.9, 0.1, -0.8, -1.0])
 | 
						|
    >>> z = np.polyfit(x, y, 3)
 | 
						|
    >>> z
 | 
						|
    array([ 0.08703704, -0.81349206,  1.69312169, -0.03968254]) # may vary
 | 
						|
 | 
						|
    It is convenient to use `poly1d` objects for dealing with polynomials:
 | 
						|
 | 
						|
    >>> p = np.poly1d(z)
 | 
						|
    >>> p(0.5)
 | 
						|
    0.6143849206349179 # may vary
 | 
						|
    >>> p(3.5)
 | 
						|
    -0.34732142857143039 # may vary
 | 
						|
    >>> p(10)
 | 
						|
    22.579365079365115 # may vary
 | 
						|
 | 
						|
    High-order polynomials may oscillate wildly:
 | 
						|
 | 
						|
    >>> with warnings.catch_warnings():
 | 
						|
    ...     warnings.simplefilter('ignore', np.exceptions.RankWarning)
 | 
						|
    ...     p30 = np.poly1d(np.polyfit(x, y, 30))
 | 
						|
    ...
 | 
						|
    >>> p30(4)
 | 
						|
    -0.80000000000000204 # may vary
 | 
						|
    >>> p30(5)
 | 
						|
    -0.99999999999999445 # may vary
 | 
						|
    >>> p30(4.5)
 | 
						|
    -0.10547061179440398 # may vary
 | 
						|
 | 
						|
    Illustration:
 | 
						|
 | 
						|
    >>> import matplotlib.pyplot as plt
 | 
						|
    >>> xp = np.linspace(-2, 6, 100)
 | 
						|
    >>> _ = plt.plot(x, y, '.', xp, p(xp), '-', xp, p30(xp), '--')
 | 
						|
    >>> plt.ylim(-2,2)
 | 
						|
    (-2, 2)
 | 
						|
    >>> plt.show()
 | 
						|
 | 
						|
    """
 | 
						|
    order = int(deg) + 1
 | 
						|
    x = NX.asarray(x) + 0.0
 | 
						|
    y = NX.asarray(y) + 0.0
 | 
						|
 | 
						|
    # check arguments.
 | 
						|
    if deg < 0:
 | 
						|
        raise ValueError("expected deg >= 0")
 | 
						|
    if x.ndim != 1:
 | 
						|
        raise TypeError("expected 1D vector for x")
 | 
						|
    if x.size == 0:
 | 
						|
        raise TypeError("expected non-empty vector for x")
 | 
						|
    if y.ndim < 1 or y.ndim > 2:
 | 
						|
        raise TypeError("expected 1D or 2D array for y")
 | 
						|
    if x.shape[0] != y.shape[0]:
 | 
						|
        raise TypeError("expected x and y to have same length")
 | 
						|
 | 
						|
    # set rcond
 | 
						|
    if rcond is None:
 | 
						|
        rcond = len(x) * finfo(x.dtype).eps
 | 
						|
 | 
						|
    # set up least squares equation for powers of x
 | 
						|
    lhs = vander(x, order)
 | 
						|
    rhs = y
 | 
						|
 | 
						|
    # apply weighting
 | 
						|
    if w is not None:
 | 
						|
        w = NX.asarray(w) + 0.0
 | 
						|
        if w.ndim != 1:
 | 
						|
            raise TypeError("expected a 1-d array for weights")
 | 
						|
        if w.shape[0] != y.shape[0]:
 | 
						|
            raise TypeError("expected w and y to have the same length")
 | 
						|
        lhs *= w[:, NX.newaxis]
 | 
						|
        if rhs.ndim == 2:
 | 
						|
            rhs *= w[:, NX.newaxis]
 | 
						|
        else:
 | 
						|
            rhs *= w
 | 
						|
 | 
						|
    # scale lhs to improve condition number and solve
 | 
						|
    scale = NX.sqrt((lhs * lhs).sum(axis=0))
 | 
						|
    lhs /= scale
 | 
						|
    c, resids, rank, s = lstsq(lhs, rhs, rcond)
 | 
						|
    c = (c.T / scale).T  # broadcast scale coefficients
 | 
						|
 | 
						|
    # warn on rank reduction, which indicates an ill conditioned matrix
 | 
						|
    if rank != order and not full:
 | 
						|
        msg = "Polyfit may be poorly conditioned"
 | 
						|
        warnings.warn(msg, RankWarning, stacklevel=2)
 | 
						|
 | 
						|
    if full:
 | 
						|
        return c, resids, rank, s, rcond
 | 
						|
    elif cov:
 | 
						|
        Vbase = inv(dot(lhs.T, lhs))
 | 
						|
        Vbase /= NX.outer(scale, scale)
 | 
						|
        if cov == "unscaled":
 | 
						|
            fac = 1
 | 
						|
        else:
 | 
						|
            if len(x) <= order:
 | 
						|
                raise ValueError("the number of data points must exceed order "
 | 
						|
                                 "to scale the covariance matrix")
 | 
						|
            # note, this used to be: fac = resids / (len(x) - order - 2.0)
 | 
						|
            # it was decided that the "- 2" (originally justified by "Bayesian
 | 
						|
            # uncertainty analysis") is not what the user expects
 | 
						|
            # (see gh-11196 and gh-11197)
 | 
						|
            fac = resids / (len(x) - order)
 | 
						|
        if y.ndim == 1:
 | 
						|
            return c, Vbase * fac
 | 
						|
        else:
 | 
						|
            return c, Vbase[:, :, NX.newaxis] * fac
 | 
						|
    else:
 | 
						|
        return c
 | 
						|
 | 
						|
 | 
						|
def _polyval_dispatcher(p, x):
 | 
						|
    return (p, x)
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_polyval_dispatcher)
 | 
						|
def polyval(p, x):
 | 
						|
    """
 | 
						|
    Evaluate a polynomial at specific values.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    If `p` is of length N, this function returns the value::
 | 
						|
 | 
						|
        p[0]*x**(N-1) + p[1]*x**(N-2) + ... + p[N-2]*x + p[N-1]
 | 
						|
 | 
						|
    If `x` is a sequence, then ``p(x)`` is returned for each element of ``x``.
 | 
						|
    If `x` is another polynomial then the composite polynomial ``p(x(t))``
 | 
						|
    is returned.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    p : array_like or poly1d object
 | 
						|
       1D array of polynomial coefficients (including coefficients equal
 | 
						|
       to zero) from highest degree to the constant term, or an
 | 
						|
       instance of poly1d.
 | 
						|
    x : array_like or poly1d object
 | 
						|
       A number, an array of numbers, or an instance of poly1d, at
 | 
						|
       which to evaluate `p`.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    values : ndarray or poly1d
 | 
						|
       If `x` is a poly1d instance, the result is the composition of the two
 | 
						|
       polynomials, i.e., `x` is "substituted" in `p` and the simplified
 | 
						|
       result is returned. In addition, the type of `x` - array_like or
 | 
						|
       poly1d - governs the type of the output: `x` array_like => `values`
 | 
						|
       array_like, `x` a poly1d object => `values` is also.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    poly1d: A polynomial class.
 | 
						|
 | 
						|
    Notes
 | 
						|
    -----
 | 
						|
    Horner's scheme [1]_ is used to evaluate the polynomial. Even so,
 | 
						|
    for polynomials of high degree the values may be inaccurate due to
 | 
						|
    rounding errors. Use carefully.
 | 
						|
 | 
						|
    If `x` is a subtype of `ndarray` the return value will be of the same type.
 | 
						|
 | 
						|
    References
 | 
						|
    ----------
 | 
						|
    .. [1] I. N. Bronshtein, K. A. Semendyayev, and K. A. Hirsch (Eng.
 | 
						|
       trans. Ed.), *Handbook of Mathematics*, New York, Van Nostrand
 | 
						|
       Reinhold Co., 1985, pg. 720.
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> import numpy as np
 | 
						|
    >>> np.polyval([3,0,1], 5)  # 3 * 5**2 + 0 * 5**1 + 1
 | 
						|
    76
 | 
						|
    >>> np.polyval([3,0,1], np.poly1d(5))
 | 
						|
    poly1d([76])
 | 
						|
    >>> np.polyval(np.poly1d([3,0,1]), 5)
 | 
						|
    76
 | 
						|
    >>> np.polyval(np.poly1d([3,0,1]), np.poly1d(5))
 | 
						|
    poly1d([76])
 | 
						|
 | 
						|
    """
 | 
						|
    p = NX.asarray(p)
 | 
						|
    if isinstance(x, poly1d):
 | 
						|
        y = 0
 | 
						|
    else:
 | 
						|
        x = NX.asanyarray(x)
 | 
						|
        y = NX.zeros_like(x)
 | 
						|
    for pv in p:
 | 
						|
        y = y * x + pv
 | 
						|
    return y
 | 
						|
 | 
						|
 | 
						|
def _binary_op_dispatcher(a1, a2):
 | 
						|
    return (a1, a2)
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_binary_op_dispatcher)
 | 
						|
def polyadd(a1, a2):
 | 
						|
    """
 | 
						|
    Find the sum of two polynomials.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    Returns the polynomial resulting from the sum of two input polynomials.
 | 
						|
    Each input must be either a poly1d object or a 1D sequence of polynomial
 | 
						|
    coefficients, from highest to lowest degree.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    a1, a2 : array_like or poly1d object
 | 
						|
        Input polynomials.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    out : ndarray or poly1d object
 | 
						|
        The sum of the inputs. If either input is a poly1d object, then the
 | 
						|
        output is also a poly1d object. Otherwise, it is a 1D array of
 | 
						|
        polynomial coefficients from highest to lowest degree.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    poly1d : A one-dimensional polynomial class.
 | 
						|
    poly, polyadd, polyder, polydiv, polyfit, polyint, polysub, polyval
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> import numpy as np
 | 
						|
    >>> np.polyadd([1, 2], [9, 5, 4])
 | 
						|
    array([9, 6, 6])
 | 
						|
 | 
						|
    Using poly1d objects:
 | 
						|
 | 
						|
    >>> p1 = np.poly1d([1, 2])
 | 
						|
    >>> p2 = np.poly1d([9, 5, 4])
 | 
						|
    >>> print(p1)
 | 
						|
    1 x + 2
 | 
						|
    >>> print(p2)
 | 
						|
       2
 | 
						|
    9 x + 5 x + 4
 | 
						|
    >>> print(np.polyadd(p1, p2))
 | 
						|
       2
 | 
						|
    9 x + 6 x + 6
 | 
						|
 | 
						|
    """
 | 
						|
    truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
 | 
						|
    a1 = atleast_1d(a1)
 | 
						|
    a2 = atleast_1d(a2)
 | 
						|
    diff = len(a2) - len(a1)
 | 
						|
    if diff == 0:
 | 
						|
        val = a1 + a2
 | 
						|
    elif diff > 0:
 | 
						|
        zr = NX.zeros(diff, a1.dtype)
 | 
						|
        val = NX.concatenate((zr, a1)) + a2
 | 
						|
    else:
 | 
						|
        zr = NX.zeros(abs(diff), a2.dtype)
 | 
						|
        val = a1 + NX.concatenate((zr, a2))
 | 
						|
    if truepoly:
 | 
						|
        val = poly1d(val)
 | 
						|
    return val
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_binary_op_dispatcher)
 | 
						|
def polysub(a1, a2):
 | 
						|
    """
 | 
						|
    Difference (subtraction) of two polynomials.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    Given two polynomials `a1` and `a2`, returns ``a1 - a2``.
 | 
						|
    `a1` and `a2` can be either array_like sequences of the polynomials'
 | 
						|
    coefficients (including coefficients equal to zero), or `poly1d` objects.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    a1, a2 : array_like or poly1d
 | 
						|
        Minuend and subtrahend polynomials, respectively.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    out : ndarray or poly1d
 | 
						|
        Array or `poly1d` object of the difference polynomial's coefficients.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    polyval, polydiv, polymul, polyadd
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
 | 
						|
    .. math:: (2 x^2 + 10 x - 2) - (3 x^2 + 10 x -4) = (-x^2 + 2)
 | 
						|
 | 
						|
    >>> import numpy as np
 | 
						|
 | 
						|
    >>> np.polysub([2, 10, -2], [3, 10, -4])
 | 
						|
    array([-1,  0,  2])
 | 
						|
 | 
						|
    """
 | 
						|
    truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
 | 
						|
    a1 = atleast_1d(a1)
 | 
						|
    a2 = atleast_1d(a2)
 | 
						|
    diff = len(a2) - len(a1)
 | 
						|
    if diff == 0:
 | 
						|
        val = a1 - a2
 | 
						|
    elif diff > 0:
 | 
						|
        zr = NX.zeros(diff, a1.dtype)
 | 
						|
        val = NX.concatenate((zr, a1)) - a2
 | 
						|
    else:
 | 
						|
        zr = NX.zeros(abs(diff), a2.dtype)
 | 
						|
        val = a1 - NX.concatenate((zr, a2))
 | 
						|
    if truepoly:
 | 
						|
        val = poly1d(val)
 | 
						|
    return val
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_binary_op_dispatcher)
 | 
						|
def polymul(a1, a2):
 | 
						|
    """
 | 
						|
    Find the product of two polynomials.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    Finds the polynomial resulting from the multiplication of the two input
 | 
						|
    polynomials. Each input must be either a poly1d object or a 1D sequence
 | 
						|
    of polynomial coefficients, from highest to lowest degree.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    a1, a2 : array_like or poly1d object
 | 
						|
        Input polynomials.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    out : ndarray or poly1d object
 | 
						|
        The polynomial resulting from the multiplication of the inputs. If
 | 
						|
        either inputs is a poly1d object, then the output is also a poly1d
 | 
						|
        object. Otherwise, it is a 1D array of polynomial coefficients from
 | 
						|
        highest to lowest degree.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    poly1d : A one-dimensional polynomial class.
 | 
						|
    poly, polyadd, polyder, polydiv, polyfit, polyint, polysub, polyval
 | 
						|
    convolve : Array convolution. Same output as polymul, but has parameter
 | 
						|
               for overlap mode.
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> import numpy as np
 | 
						|
    >>> np.polymul([1, 2, 3], [9, 5, 1])
 | 
						|
    array([ 9, 23, 38, 17,  3])
 | 
						|
 | 
						|
    Using poly1d objects:
 | 
						|
 | 
						|
    >>> p1 = np.poly1d([1, 2, 3])
 | 
						|
    >>> p2 = np.poly1d([9, 5, 1])
 | 
						|
    >>> print(p1)
 | 
						|
       2
 | 
						|
    1 x + 2 x + 3
 | 
						|
    >>> print(p2)
 | 
						|
       2
 | 
						|
    9 x + 5 x + 1
 | 
						|
    >>> print(np.polymul(p1, p2))
 | 
						|
       4      3      2
 | 
						|
    9 x + 23 x + 38 x + 17 x + 3
 | 
						|
 | 
						|
    """
 | 
						|
    truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
 | 
						|
    a1, a2 = poly1d(a1), poly1d(a2)
 | 
						|
    val = NX.convolve(a1, a2)
 | 
						|
    if truepoly:
 | 
						|
        val = poly1d(val)
 | 
						|
    return val
 | 
						|
 | 
						|
 | 
						|
def _polydiv_dispatcher(u, v):
 | 
						|
    return (u, v)
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_polydiv_dispatcher)
 | 
						|
def polydiv(u, v):
 | 
						|
    """
 | 
						|
    Returns the quotient and remainder of polynomial division.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    The input arrays are the coefficients (including any coefficients
 | 
						|
    equal to zero) of the "numerator" (dividend) and "denominator"
 | 
						|
    (divisor) polynomials, respectively.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    u : array_like or poly1d
 | 
						|
        Dividend polynomial's coefficients.
 | 
						|
 | 
						|
    v : array_like or poly1d
 | 
						|
        Divisor polynomial's coefficients.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    q : ndarray
 | 
						|
        Coefficients, including those equal to zero, of the quotient.
 | 
						|
    r : ndarray
 | 
						|
        Coefficients, including those equal to zero, of the remainder.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    poly, polyadd, polyder, polydiv, polyfit, polyint, polymul, polysub
 | 
						|
    polyval
 | 
						|
 | 
						|
    Notes
 | 
						|
    -----
 | 
						|
    Both `u` and `v` must be 0-d or 1-d (ndim = 0 or 1), but `u.ndim` need
 | 
						|
    not equal `v.ndim`. In other words, all four possible combinations -
 | 
						|
    ``u.ndim = v.ndim = 0``, ``u.ndim = v.ndim = 1``,
 | 
						|
    ``u.ndim = 1, v.ndim = 0``, and ``u.ndim = 0, v.ndim = 1`` - work.
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
 | 
						|
    .. math:: \\frac{3x^2 + 5x + 2}{2x + 1} = 1.5x + 1.75, remainder 0.25
 | 
						|
 | 
						|
    >>> import numpy as np
 | 
						|
 | 
						|
    >>> x = np.array([3.0, 5.0, 2.0])
 | 
						|
    >>> y = np.array([2.0, 1.0])
 | 
						|
    >>> np.polydiv(x, y)
 | 
						|
    (array([1.5 , 1.75]), array([0.25]))
 | 
						|
 | 
						|
    """
 | 
						|
    truepoly = (isinstance(u, poly1d) or isinstance(v, poly1d))
 | 
						|
    u = atleast_1d(u) + 0.0
 | 
						|
    v = atleast_1d(v) + 0.0
 | 
						|
    # w has the common type
 | 
						|
    w = u[0] + v[0]
 | 
						|
    m = len(u) - 1
 | 
						|
    n = len(v) - 1
 | 
						|
    scale = 1. / v[0]
 | 
						|
    q = NX.zeros((max(m - n + 1, 1),), w.dtype)
 | 
						|
    r = u.astype(w.dtype)
 | 
						|
    for k in range(m - n + 1):
 | 
						|
        d = scale * r[k]
 | 
						|
        q[k] = d
 | 
						|
        r[k:k + n + 1] -= d * v
 | 
						|
    while NX.allclose(r[0], 0, rtol=1e-14) and (r.shape[-1] > 1):
 | 
						|
        r = r[1:]
 | 
						|
    if truepoly:
 | 
						|
        return poly1d(q), poly1d(r)
 | 
						|
    return q, r
 | 
						|
 | 
						|
 | 
						|
_poly_mat = re.compile(r"\*\*([0-9]*)")
 | 
						|
def _raise_power(astr, wrap=70):
 | 
						|
    n = 0
 | 
						|
    line1 = ''
 | 
						|
    line2 = ''
 | 
						|
    output = ' '
 | 
						|
    while True:
 | 
						|
        mat = _poly_mat.search(astr, n)
 | 
						|
        if mat is None:
 | 
						|
            break
 | 
						|
        span = mat.span()
 | 
						|
        power = mat.groups()[0]
 | 
						|
        partstr = astr[n:span[0]]
 | 
						|
        n = span[1]
 | 
						|
        toadd2 = partstr + ' ' * (len(power) - 1)
 | 
						|
        toadd1 = ' ' * (len(partstr) - 1) + power
 | 
						|
        if ((len(line2) + len(toadd2) > wrap) or
 | 
						|
                (len(line1) + len(toadd1) > wrap)):
 | 
						|
            output += line1 + "\n" + line2 + "\n "
 | 
						|
            line1 = toadd1
 | 
						|
            line2 = toadd2
 | 
						|
        else:
 | 
						|
            line2 += partstr + ' ' * (len(power) - 1)
 | 
						|
            line1 += ' ' * (len(partstr) - 1) + power
 | 
						|
    output += line1 + "\n" + line2
 | 
						|
    return output + astr[n:]
 | 
						|
 | 
						|
 | 
						|
@set_module('numpy')
 | 
						|
class poly1d:
 | 
						|
    """
 | 
						|
    A one-dimensional polynomial class.
 | 
						|
 | 
						|
    .. note::
 | 
						|
       This forms part of the old polynomial API. Since version 1.4, the
 | 
						|
       new polynomial API defined in `numpy.polynomial` is preferred.
 | 
						|
       A summary of the differences can be found in the
 | 
						|
       :doc:`transition guide </reference/routines.polynomials>`.
 | 
						|
 | 
						|
    A convenience class, used to encapsulate "natural" operations on
 | 
						|
    polynomials so that said operations may take on their customary
 | 
						|
    form in code (see Examples).
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    c_or_r : array_like
 | 
						|
        The polynomial's coefficients, in decreasing powers, or if
 | 
						|
        the value of the second parameter is True, the polynomial's
 | 
						|
        roots (values where the polynomial evaluates to 0).  For example,
 | 
						|
        ``poly1d([1, 2, 3])`` returns an object that represents
 | 
						|
        :math:`x^2 + 2x + 3`, whereas ``poly1d([1, 2, 3], True)`` returns
 | 
						|
        one that represents :math:`(x-1)(x-2)(x-3) = x^3 - 6x^2 + 11x -6`.
 | 
						|
    r : bool, optional
 | 
						|
        If True, `c_or_r` specifies the polynomial's roots; the default
 | 
						|
        is False.
 | 
						|
    variable : str, optional
 | 
						|
        Changes the variable used when printing `p` from `x` to `variable`
 | 
						|
        (see Examples).
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> import numpy as np
 | 
						|
 | 
						|
    Construct the polynomial :math:`x^2 + 2x + 3`:
 | 
						|
 | 
						|
    >>> import numpy as np
 | 
						|
 | 
						|
    >>> p = np.poly1d([1, 2, 3])
 | 
						|
    >>> print(np.poly1d(p))
 | 
						|
       2
 | 
						|
    1 x + 2 x + 3
 | 
						|
 | 
						|
    Evaluate the polynomial at :math:`x = 0.5`:
 | 
						|
 | 
						|
    >>> p(0.5)
 | 
						|
    4.25
 | 
						|
 | 
						|
    Find the roots:
 | 
						|
 | 
						|
    >>> p.r
 | 
						|
    array([-1.+1.41421356j, -1.-1.41421356j])
 | 
						|
    >>> p(p.r)
 | 
						|
    array([ -4.44089210e-16+0.j,  -4.44089210e-16+0.j]) # may vary
 | 
						|
 | 
						|
    These numbers in the previous line represent (0, 0) to machine precision
 | 
						|
 | 
						|
    Show the coefficients:
 | 
						|
 | 
						|
    >>> p.c
 | 
						|
    array([1, 2, 3])
 | 
						|
 | 
						|
    Display the order (the leading zero-coefficients are removed):
 | 
						|
 | 
						|
    >>> p.order
 | 
						|
    2
 | 
						|
 | 
						|
    Show the coefficient of the k-th power in the polynomial
 | 
						|
    (which is equivalent to ``p.c[-(i+1)]``):
 | 
						|
 | 
						|
    >>> p[1]
 | 
						|
    2
 | 
						|
 | 
						|
    Polynomials can be added, subtracted, multiplied, and divided
 | 
						|
    (returns quotient and remainder):
 | 
						|
 | 
						|
    >>> p * p
 | 
						|
    poly1d([ 1,  4, 10, 12,  9])
 | 
						|
 | 
						|
    >>> (p**3 + 4) / p
 | 
						|
    (poly1d([ 1.,  4., 10., 12.,  9.]), poly1d([4.]))
 | 
						|
 | 
						|
    ``asarray(p)`` gives the coefficient array, so polynomials can be
 | 
						|
    used in all functions that accept arrays:
 | 
						|
 | 
						|
    >>> p**2 # square of polynomial
 | 
						|
    poly1d([ 1,  4, 10, 12,  9])
 | 
						|
 | 
						|
    >>> np.square(p) # square of individual coefficients
 | 
						|
    array([1, 4, 9])
 | 
						|
 | 
						|
    The variable used in the string representation of `p` can be modified,
 | 
						|
    using the `variable` parameter:
 | 
						|
 | 
						|
    >>> p = np.poly1d([1,2,3], variable='z')
 | 
						|
    >>> print(p)
 | 
						|
       2
 | 
						|
    1 z + 2 z + 3
 | 
						|
 | 
						|
    Construct a polynomial from its roots:
 | 
						|
 | 
						|
    >>> np.poly1d([1, 2], True)
 | 
						|
    poly1d([ 1., -3.,  2.])
 | 
						|
 | 
						|
    This is the same polynomial as obtained by:
 | 
						|
 | 
						|
    >>> np.poly1d([1, -1]) * np.poly1d([1, -2])
 | 
						|
    poly1d([ 1, -3,  2])
 | 
						|
 | 
						|
    """
 | 
						|
    __hash__ = None
 | 
						|
 | 
						|
    @property
 | 
						|
    def coeffs(self):
 | 
						|
        """ The polynomial coefficients """
 | 
						|
        return self._coeffs
 | 
						|
 | 
						|
    @coeffs.setter
 | 
						|
    def coeffs(self, value):
 | 
						|
        # allowing this makes p.coeffs *= 2 legal
 | 
						|
        if value is not self._coeffs:
 | 
						|
            raise AttributeError("Cannot set attribute")
 | 
						|
 | 
						|
    @property
 | 
						|
    def variable(self):
 | 
						|
        """ The name of the polynomial variable """
 | 
						|
        return self._variable
 | 
						|
 | 
						|
    # calculated attributes
 | 
						|
    @property
 | 
						|
    def order(self):
 | 
						|
        """ The order or degree of the polynomial """
 | 
						|
        return len(self._coeffs) - 1
 | 
						|
 | 
						|
    @property
 | 
						|
    def roots(self):
 | 
						|
        """ The roots of the polynomial, where self(x) == 0 """
 | 
						|
        return roots(self._coeffs)
 | 
						|
 | 
						|
    # our internal _coeffs property need to be backed by __dict__['coeffs'] for
 | 
						|
    # scipy to work correctly.
 | 
						|
    @property
 | 
						|
    def _coeffs(self):
 | 
						|
        return self.__dict__['coeffs']
 | 
						|
 | 
						|
    @_coeffs.setter
 | 
						|
    def _coeffs(self, coeffs):
 | 
						|
        self.__dict__['coeffs'] = coeffs
 | 
						|
 | 
						|
    # alias attributes
 | 
						|
    r = roots
 | 
						|
    c = coef = coefficients = coeffs
 | 
						|
    o = order
 | 
						|
 | 
						|
    def __init__(self, c_or_r, r=False, variable=None):
 | 
						|
        if isinstance(c_or_r, poly1d):
 | 
						|
            self._variable = c_or_r._variable
 | 
						|
            self._coeffs = c_or_r._coeffs
 | 
						|
 | 
						|
            if set(c_or_r.__dict__) - set(self.__dict__):
 | 
						|
                msg = ("In the future extra properties will not be copied "
 | 
						|
                       "across when constructing one poly1d from another")
 | 
						|
                warnings.warn(msg, FutureWarning, stacklevel=2)
 | 
						|
                self.__dict__.update(c_or_r.__dict__)
 | 
						|
 | 
						|
            if variable is not None:
 | 
						|
                self._variable = variable
 | 
						|
            return
 | 
						|
        if r:
 | 
						|
            c_or_r = poly(c_or_r)
 | 
						|
        c_or_r = atleast_1d(c_or_r)
 | 
						|
        if c_or_r.ndim > 1:
 | 
						|
            raise ValueError("Polynomial must be 1d only.")
 | 
						|
        c_or_r = trim_zeros(c_or_r, trim='f')
 | 
						|
        if len(c_or_r) == 0:
 | 
						|
            c_or_r = NX.array([0], dtype=c_or_r.dtype)
 | 
						|
        self._coeffs = c_or_r
 | 
						|
        if variable is None:
 | 
						|
            variable = 'x'
 | 
						|
        self._variable = variable
 | 
						|
 | 
						|
    def __array__(self, t=None, copy=None):
 | 
						|
        if t:
 | 
						|
            return NX.asarray(self.coeffs, t, copy=copy)
 | 
						|
        else:
 | 
						|
            return NX.asarray(self.coeffs, copy=copy)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        vals = repr(self.coeffs)
 | 
						|
        vals = vals[6:-1]
 | 
						|
        return f"poly1d({vals})"
 | 
						|
 | 
						|
    def __len__(self):
 | 
						|
        return self.order
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        thestr = "0"
 | 
						|
        var = self.variable
 | 
						|
 | 
						|
        # Remove leading zeros
 | 
						|
        coeffs = self.coeffs[NX.logical_or.accumulate(self.coeffs != 0)]
 | 
						|
        N = len(coeffs) - 1
 | 
						|
 | 
						|
        def fmt_float(q):
 | 
						|
            s = f'{q:.4g}'
 | 
						|
            s = s.removesuffix('.0000')
 | 
						|
            return s
 | 
						|
 | 
						|
        for k, coeff in enumerate(coeffs):
 | 
						|
            if not iscomplex(coeff):
 | 
						|
                coefstr = fmt_float(real(coeff))
 | 
						|
            elif real(coeff) == 0:
 | 
						|
                coefstr = f'{fmt_float(imag(coeff))}j'
 | 
						|
            else:
 | 
						|
                coefstr = f'({fmt_float(real(coeff))} + {fmt_float(imag(coeff))}j)'
 | 
						|
 | 
						|
            power = (N - k)
 | 
						|
            if power == 0:
 | 
						|
                if coefstr != '0':
 | 
						|
                    newstr = f'{coefstr}'
 | 
						|
                elif k == 0:
 | 
						|
                    newstr = '0'
 | 
						|
                else:
 | 
						|
                    newstr = ''
 | 
						|
            elif power == 1:
 | 
						|
                if coefstr == '0':
 | 
						|
                    newstr = ''
 | 
						|
                elif coefstr == 'b':
 | 
						|
                    newstr = var
 | 
						|
                else:
 | 
						|
                    newstr = f'{coefstr} {var}'
 | 
						|
            elif coefstr == '0':
 | 
						|
                newstr = ''
 | 
						|
            elif coefstr == 'b':
 | 
						|
                newstr = '%s**%d' % (var, power,)
 | 
						|
            else:
 | 
						|
                newstr = '%s %s**%d' % (coefstr, var, power)
 | 
						|
 | 
						|
            if k > 0:
 | 
						|
                if newstr != '':
 | 
						|
                    if newstr.startswith('-'):
 | 
						|
                        thestr = f"{thestr} - {newstr[1:]}"
 | 
						|
                    else:
 | 
						|
                        thestr = f"{thestr} + {newstr}"
 | 
						|
            else:
 | 
						|
                thestr = newstr
 | 
						|
        return _raise_power(thestr)
 | 
						|
 | 
						|
    def __call__(self, val):
 | 
						|
        return polyval(self.coeffs, val)
 | 
						|
 | 
						|
    def __neg__(self):
 | 
						|
        return poly1d(-self.coeffs)
 | 
						|
 | 
						|
    def __pos__(self):
 | 
						|
        return self
 | 
						|
 | 
						|
    def __mul__(self, other):
 | 
						|
        if isscalar(other):
 | 
						|
            return poly1d(self.coeffs * other)
 | 
						|
        else:
 | 
						|
            other = poly1d(other)
 | 
						|
            return poly1d(polymul(self.coeffs, other.coeffs))
 | 
						|
 | 
						|
    def __rmul__(self, other):
 | 
						|
        if isscalar(other):
 | 
						|
            return poly1d(other * self.coeffs)
 | 
						|
        else:
 | 
						|
            other = poly1d(other)
 | 
						|
            return poly1d(polymul(self.coeffs, other.coeffs))
 | 
						|
 | 
						|
    def __add__(self, other):
 | 
						|
        other = poly1d(other)
 | 
						|
        return poly1d(polyadd(self.coeffs, other.coeffs))
 | 
						|
 | 
						|
    def __radd__(self, other):
 | 
						|
        other = poly1d(other)
 | 
						|
        return poly1d(polyadd(self.coeffs, other.coeffs))
 | 
						|
 | 
						|
    def __pow__(self, val):
 | 
						|
        if not isscalar(val) or int(val) != val or val < 0:
 | 
						|
            raise ValueError("Power to non-negative integers only.")
 | 
						|
        res = [1]
 | 
						|
        for _ in range(val):
 | 
						|
            res = polymul(self.coeffs, res)
 | 
						|
        return poly1d(res)
 | 
						|
 | 
						|
    def __sub__(self, other):
 | 
						|
        other = poly1d(other)
 | 
						|
        return poly1d(polysub(self.coeffs, other.coeffs))
 | 
						|
 | 
						|
    def __rsub__(self, other):
 | 
						|
        other = poly1d(other)
 | 
						|
        return poly1d(polysub(other.coeffs, self.coeffs))
 | 
						|
 | 
						|
    def __truediv__(self, other):
 | 
						|
        if isscalar(other):
 | 
						|
            return poly1d(self.coeffs / other)
 | 
						|
        else:
 | 
						|
            other = poly1d(other)
 | 
						|
            return polydiv(self, other)
 | 
						|
 | 
						|
    def __rtruediv__(self, other):
 | 
						|
        if isscalar(other):
 | 
						|
            return poly1d(other / self.coeffs)
 | 
						|
        else:
 | 
						|
            other = poly1d(other)
 | 
						|
            return polydiv(other, self)
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if not isinstance(other, poly1d):
 | 
						|
            return NotImplemented
 | 
						|
        if self.coeffs.shape != other.coeffs.shape:
 | 
						|
            return False
 | 
						|
        return (self.coeffs == other.coeffs).all()
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if not isinstance(other, poly1d):
 | 
						|
            return NotImplemented
 | 
						|
        return not self.__eq__(other)
 | 
						|
 | 
						|
    def __getitem__(self, val):
 | 
						|
        ind = self.order - val
 | 
						|
        if val > self.order:
 | 
						|
            return self.coeffs.dtype.type(0)
 | 
						|
        if val < 0:
 | 
						|
            return self.coeffs.dtype.type(0)
 | 
						|
        return self.coeffs[ind]
 | 
						|
 | 
						|
    def __setitem__(self, key, val):
 | 
						|
        ind = self.order - key
 | 
						|
        if key < 0:
 | 
						|
            raise ValueError("Does not support negative powers.")
 | 
						|
        if key > self.order:
 | 
						|
            zr = NX.zeros(key - self.order, self.coeffs.dtype)
 | 
						|
            self._coeffs = NX.concatenate((zr, self.coeffs))
 | 
						|
            ind = 0
 | 
						|
        self._coeffs[ind] = val
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        return iter(self.coeffs)
 | 
						|
 | 
						|
    def integ(self, m=1, k=0):
 | 
						|
        """
 | 
						|
        Return an antiderivative (indefinite integral) of this polynomial.
 | 
						|
 | 
						|
        Refer to `polyint` for full documentation.
 | 
						|
 | 
						|
        See Also
 | 
						|
        --------
 | 
						|
        polyint : equivalent function
 | 
						|
 | 
						|
        """
 | 
						|
        return poly1d(polyint(self.coeffs, m=m, k=k))
 | 
						|
 | 
						|
    def deriv(self, m=1):
 | 
						|
        """
 | 
						|
        Return a derivative of this polynomial.
 | 
						|
 | 
						|
        Refer to `polyder` for full documentation.
 | 
						|
 | 
						|
        See Also
 | 
						|
        --------
 | 
						|
        polyder : equivalent function
 | 
						|
 | 
						|
        """
 | 
						|
        return poly1d(polyder(self.coeffs, m=m))
 | 
						|
 | 
						|
# Stuff to do on module import
 | 
						|
 | 
						|
 | 
						|
warnings.simplefilter('always', RankWarning)
 |