You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					790 lines
				
				23 KiB
			
		
		
			
		
	
	
					790 lines
				
				23 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"""
							 | 
						||
| 
								 | 
							
								Utility classes and functions for the polynomial modules.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This module provides: error and warning objects; a polynomial base class;
							 | 
						||
| 
								 | 
							
								and some routines used in both the `polynomial` and `chebyshev` modules.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Warning objects
							 | 
						||
| 
								 | 
							
								---------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. autosummary::
							 | 
						||
| 
								 | 
							
								   :toctree: generated/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   RankWarning  raised in least-squares fit for rank-deficient matrix.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Functions
							 | 
						||
| 
								 | 
							
								---------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. autosummary::
							 | 
						||
| 
								 | 
							
								   :toctree: generated/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   as_series    convert list of array_likes into 1-D arrays of common type.
							 | 
						||
| 
								 | 
							
								   trimseq      remove trailing zeros.
							 | 
						||
| 
								 | 
							
								   trimcoef     remove small trailing coefficients.
							 | 
						||
| 
								 | 
							
								   getdomain    return the domain appropriate for a given set of abscissae.
							 | 
						||
| 
								 | 
							
								   mapdomain    maps points between domains.
							 | 
						||
| 
								 | 
							
								   mapparms     parameters of the linear map between domains.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								import operator
							 | 
						||
| 
								 | 
							
								import functools
							 | 
						||
| 
								 | 
							
								import warnings
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import numpy as np
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from numpy.core.multiarray import dragon4_positional, dragon4_scientific
							 | 
						||
| 
								 | 
							
								from numpy.core.umath import absolute
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								__all__ = [
							 | 
						||
| 
								 | 
							
								    'RankWarning', 'as_series', 'trimseq',
							 | 
						||
| 
								 | 
							
								    'trimcoef', 'getdomain', 'mapdomain', 'mapparms',
							 | 
						||
| 
								 | 
							
								    'format_float']
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Warnings and Exceptions
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class RankWarning(UserWarning):
							 | 
						||
| 
								 | 
							
								    """Issued by chebfit when the design matrix is rank deficient."""
							 | 
						||
| 
								 | 
							
								    pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Helper functions to convert inputs to 1-D arrays
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								def trimseq(seq):
							 | 
						||
| 
								 | 
							
								    """Remove small Poly series coefficients.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    seq : sequence
							 | 
						||
| 
								 | 
							
								        Sequence of Poly series coefficients. This routine fails for
							 | 
						||
| 
								 | 
							
								        empty sequences.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    series : sequence
							 | 
						||
| 
								 | 
							
								        Subsequence with trailing zeros removed. If the resulting sequence
							 | 
						||
| 
								 | 
							
								        would be empty, return the first element. The returned sequence may
							 | 
						||
| 
								 | 
							
								        or may not be a view.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Notes
							 | 
						||
| 
								 | 
							
								    -----
							 | 
						||
| 
								 | 
							
								    Do not lose the type info if the sequence contains unknown objects.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if len(seq) == 0:
							 | 
						||
| 
								 | 
							
								        return seq
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        for i in range(len(seq) - 1, -1, -1):
							 | 
						||
| 
								 | 
							
								            if seq[i] != 0:
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								        return seq[:i+1]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def as_series(alist, trim=True):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Return argument as a list of 1-d arrays.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The returned list contains array(s) of dtype double, complex double, or
							 | 
						||
| 
								 | 
							
								    object.  A 1-d argument of shape ``(N,)`` is parsed into ``N`` arrays of
							 | 
						||
| 
								 | 
							
								    size one; a 2-d argument of shape ``(M,N)`` is parsed into ``M`` arrays
							 | 
						||
| 
								 | 
							
								    of size ``N`` (i.e., is "parsed by row"); and a higher dimensional array
							 | 
						||
| 
								 | 
							
								    raises a Value Error if it is not first reshaped into either a 1-d or 2-d
							 | 
						||
| 
								 | 
							
								    array.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    alist : array_like
							 | 
						||
| 
								 | 
							
								        A 1- or 2-d array_like
							 | 
						||
| 
								 | 
							
								    trim : boolean, optional
							 | 
						||
| 
								 | 
							
								        When True, trailing zeros are removed from the inputs.
							 | 
						||
| 
								 | 
							
								        When False, the inputs are passed through intact.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    [a1, a2,...] : list of 1-D arrays
							 | 
						||
| 
								 | 
							
								        A copy of the input data as a list of 1-d arrays.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Raises
							 | 
						||
| 
								 | 
							
								    ------
							 | 
						||
| 
								 | 
							
								    ValueError
							 | 
						||
| 
								 | 
							
								        Raised when `as_series` cannot convert its input to 1-d arrays, or at
							 | 
						||
| 
								 | 
							
								        least one of the resulting arrays is empty.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Examples
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    >>> from numpy.polynomial import polyutils as pu
							 | 
						||
| 
								 | 
							
								    >>> a = np.arange(4)
							 | 
						||
| 
								 | 
							
								    >>> pu.as_series(a)
							 | 
						||
| 
								 | 
							
								    [array([0.]), array([1.]), array([2.]), array([3.])]
							 | 
						||
| 
								 | 
							
								    >>> b = np.arange(6).reshape((2,3))
							 | 
						||
| 
								 | 
							
								    >>> pu.as_series(b)
							 | 
						||
| 
								 | 
							
								    [array([0., 1., 2.]), array([3., 4., 5.])]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> pu.as_series((1, np.arange(3), np.arange(2, dtype=np.float16)))
							 | 
						||
| 
								 | 
							
								    [array([1.]), array([0., 1., 2.]), array([0., 1.])]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> pu.as_series([2, [1.1, 0.]])
							 | 
						||
| 
								 | 
							
								    [array([2.]), array([1.1])]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> pu.as_series([2, [1.1, 0.]], trim=False)
							 | 
						||
| 
								 | 
							
								    [array([2.]), array([1.1, 0. ])]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    arrays = [np.array(a, ndmin=1, copy=False) for a in alist]
							 | 
						||
| 
								 | 
							
								    if min([a.size for a in arrays]) == 0:
							 | 
						||
| 
								 | 
							
								        raise ValueError("Coefficient array is empty")
							 | 
						||
| 
								 | 
							
								    if any(a.ndim != 1 for a in arrays):
							 | 
						||
| 
								 | 
							
								        raise ValueError("Coefficient array is not 1-d")
							 | 
						||
| 
								 | 
							
								    if trim:
							 | 
						||
| 
								 | 
							
								        arrays = [trimseq(a) for a in arrays]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if any(a.dtype == np.dtype(object) for a in arrays):
							 | 
						||
| 
								 | 
							
								        ret = []
							 | 
						||
| 
								 | 
							
								        for a in arrays:
							 | 
						||
| 
								 | 
							
								            if a.dtype != np.dtype(object):
							 | 
						||
| 
								 | 
							
								                tmp = np.empty(len(a), dtype=np.dtype(object))
							 | 
						||
| 
								 | 
							
								                tmp[:] = a[:]
							 | 
						||
| 
								 | 
							
								                ret.append(tmp)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                ret.append(a.copy())
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            dtype = np.common_type(*arrays)
							 | 
						||
| 
								 | 
							
								        except Exception as e:
							 | 
						||
| 
								 | 
							
								            raise ValueError("Coefficient arrays have no common type") from e
							 | 
						||
| 
								 | 
							
								        ret = [np.array(a, copy=True, dtype=dtype) for a in arrays]
							 | 
						||
| 
								 | 
							
								    return ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def trimcoef(c, tol=0):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Remove "small" "trailing" coefficients from a polynomial.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "Small" means "small in absolute value" and is controlled by the
							 | 
						||
| 
								 | 
							
								    parameter `tol`; "trailing" means highest order coefficient(s), e.g., in
							 | 
						||
| 
								 | 
							
								    ``[0, 1, 1, 0, 0]`` (which represents ``0 + x + x**2 + 0*x**3 + 0*x**4``)
							 | 
						||
| 
								 | 
							
								    both the 3-rd and 4-th order coefficients would be "trimmed."
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    c : array_like
							 | 
						||
| 
								 | 
							
								        1-d array of coefficients, ordered from lowest order to highest.
							 | 
						||
| 
								 | 
							
								    tol : number, optional
							 | 
						||
| 
								 | 
							
								        Trailing (i.e., highest order) elements with absolute value less
							 | 
						||
| 
								 | 
							
								        than or equal to `tol` (default value is zero) are removed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    trimmed : ndarray
							 | 
						||
| 
								 | 
							
								        1-d array with trailing zeros removed.  If the resulting series
							 | 
						||
| 
								 | 
							
								        would be empty, a series containing a single zero is returned.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Raises
							 | 
						||
| 
								 | 
							
								    ------
							 | 
						||
| 
								 | 
							
								    ValueError
							 | 
						||
| 
								 | 
							
								        If `tol` < 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    See Also
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    trimseq
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Examples
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    >>> from numpy.polynomial import polyutils as pu
							 | 
						||
| 
								 | 
							
								    >>> pu.trimcoef((0,0,3,0,5,0,0))
							 | 
						||
| 
								 | 
							
								    array([0.,  0.,  3.,  0.,  5.])
							 | 
						||
| 
								 | 
							
								    >>> pu.trimcoef((0,0,1e-3,0,1e-5,0,0),1e-3) # item == tol is trimmed
							 | 
						||
| 
								 | 
							
								    array([0.])
							 | 
						||
| 
								 | 
							
								    >>> i = complex(0,1) # works for complex
							 | 
						||
| 
								 | 
							
								    >>> pu.trimcoef((3e-4,1e-3*(1-i),5e-4,2e-5*(1+i)), 1e-3)
							 | 
						||
| 
								 | 
							
								    array([0.0003+0.j   , 0.001 -0.001j])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if tol < 0:
							 | 
						||
| 
								 | 
							
								        raise ValueError("tol must be non-negative")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [c] = as_series([c])
							 | 
						||
| 
								 | 
							
								    [ind] = np.nonzero(np.abs(c) > tol)
							 | 
						||
| 
								 | 
							
								    if len(ind) == 0:
							 | 
						||
| 
								 | 
							
								        return c[:1]*0
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return c[:ind[-1] + 1].copy()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def getdomain(x):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Return a domain suitable for given abscissae.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Find a domain suitable for a polynomial or Chebyshev series
							 | 
						||
| 
								 | 
							
								    defined at the values supplied.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    x : array_like
							 | 
						||
| 
								 | 
							
								        1-d array of abscissae whose domain will be determined.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    domain : ndarray
							 | 
						||
| 
								 | 
							
								        1-d array containing two values.  If the inputs are complex, then
							 | 
						||
| 
								 | 
							
								        the two returned points are the lower left and upper right corners
							 | 
						||
| 
								 | 
							
								        of the smallest rectangle (aligned with the axes) in the complex
							 | 
						||
| 
								 | 
							
								        plane containing the points `x`. If the inputs are real, then the
							 | 
						||
| 
								 | 
							
								        two points are the ends of the smallest interval containing the
							 | 
						||
| 
								 | 
							
								        points `x`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    See Also
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    mapparms, mapdomain
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Examples
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    >>> from numpy.polynomial import polyutils as pu
							 | 
						||
| 
								 | 
							
								    >>> points = np.arange(4)**2 - 5; points
							 | 
						||
| 
								 | 
							
								    array([-5, -4, -1,  4])
							 | 
						||
| 
								 | 
							
								    >>> pu.getdomain(points)
							 | 
						||
| 
								 | 
							
								    array([-5.,  4.])
							 | 
						||
| 
								 | 
							
								    >>> c = np.exp(complex(0,1)*np.pi*np.arange(12)/6) # unit circle
							 | 
						||
| 
								 | 
							
								    >>> pu.getdomain(c)
							 | 
						||
| 
								 | 
							
								    array([-1.-1.j,  1.+1.j])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    [x] = as_series([x], trim=False)
							 | 
						||
| 
								 | 
							
								    if x.dtype.char in np.typecodes['Complex']:
							 | 
						||
| 
								 | 
							
								        rmin, rmax = x.real.min(), x.real.max()
							 | 
						||
| 
								 | 
							
								        imin, imax = x.imag.min(), x.imag.max()
							 | 
						||
| 
								 | 
							
								        return np.array((complex(rmin, imin), complex(rmax, imax)))
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return np.array((x.min(), x.max()))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def mapparms(old, new):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Linear map parameters between domains.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Return the parameters of the linear map ``offset + scale*x`` that maps
							 | 
						||
| 
								 | 
							
								    `old` to `new` such that ``old[i] -> new[i]``, ``i = 0, 1``.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    old, new : array_like
							 | 
						||
| 
								 | 
							
								        Domains. Each domain must (successfully) convert to a 1-d array
							 | 
						||
| 
								 | 
							
								        containing precisely two values.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    offset, scale : scalars
							 | 
						||
| 
								 | 
							
								        The map ``L(x) = offset + scale*x`` maps the first domain to the
							 | 
						||
| 
								 | 
							
								        second.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    See Also
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    getdomain, mapdomain
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Notes
							 | 
						||
| 
								 | 
							
								    -----
							 | 
						||
| 
								 | 
							
								    Also works for complex numbers, and thus can be used to calculate the
							 | 
						||
| 
								 | 
							
								    parameters required to map any line in the complex plane to any other
							 | 
						||
| 
								 | 
							
								    line therein.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Examples
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    >>> from numpy.polynomial import polyutils as pu
							 | 
						||
| 
								 | 
							
								    >>> pu.mapparms((-1,1),(-1,1))
							 | 
						||
| 
								 | 
							
								    (0.0, 1.0)
							 | 
						||
| 
								 | 
							
								    >>> pu.mapparms((1,-1),(-1,1))
							 | 
						||
| 
								 | 
							
								    (-0.0, -1.0)
							 | 
						||
| 
								 | 
							
								    >>> i = complex(0,1)
							 | 
						||
| 
								 | 
							
								    >>> pu.mapparms((-i,-1),(1,i))
							 | 
						||
| 
								 | 
							
								    ((1+1j), (1-0j))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    oldlen = old[1] - old[0]
							 | 
						||
| 
								 | 
							
								    newlen = new[1] - new[0]
							 | 
						||
| 
								 | 
							
								    off = (old[1]*new[0] - old[0]*new[1])/oldlen
							 | 
						||
| 
								 | 
							
								    scl = newlen/oldlen
							 | 
						||
| 
								 | 
							
								    return off, scl
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def mapdomain(x, old, new):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Apply linear map to input points.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The linear map ``offset + scale*x`` that maps the domain `old` to
							 | 
						||
| 
								 | 
							
								    the domain `new` is applied to the points `x`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    x : array_like
							 | 
						||
| 
								 | 
							
								        Points to be mapped. If `x` is a subtype of ndarray the subtype
							 | 
						||
| 
								 | 
							
								        will be preserved.
							 | 
						||
| 
								 | 
							
								    old, new : array_like
							 | 
						||
| 
								 | 
							
								        The two domains that determine the map.  Each must (successfully)
							 | 
						||
| 
								 | 
							
								        convert to 1-d arrays containing precisely two values.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    x_out : ndarray
							 | 
						||
| 
								 | 
							
								        Array of points of the same shape as `x`, after application of the
							 | 
						||
| 
								 | 
							
								        linear map between the two domains.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    See Also
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    getdomain, mapparms
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Notes
							 | 
						||
| 
								 | 
							
								    -----
							 | 
						||
| 
								 | 
							
								    Effectively, this implements:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. math::
							 | 
						||
| 
								 | 
							
								        x\\_out = new[0] + m(x - old[0])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    where
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. math::
							 | 
						||
| 
								 | 
							
								        m = \\frac{new[1]-new[0]}{old[1]-old[0]}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Examples
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    >>> from numpy.polynomial import polyutils as pu
							 | 
						||
| 
								 | 
							
								    >>> old_domain = (-1,1)
							 | 
						||
| 
								 | 
							
								    >>> new_domain = (0,2*np.pi)
							 | 
						||
| 
								 | 
							
								    >>> x = np.linspace(-1,1,6); x
							 | 
						||
| 
								 | 
							
								    array([-1. , -0.6, -0.2,  0.2,  0.6,  1. ])
							 | 
						||
| 
								 | 
							
								    >>> x_out = pu.mapdomain(x, old_domain, new_domain); x_out
							 | 
						||
| 
								 | 
							
								    array([ 0.        ,  1.25663706,  2.51327412,  3.76991118,  5.02654825, # may vary
							 | 
						||
| 
								 | 
							
								            6.28318531])
							 | 
						||
| 
								 | 
							
								    >>> x - pu.mapdomain(x_out, new_domain, old_domain)
							 | 
						||
| 
								 | 
							
								    array([0., 0., 0., 0., 0., 0.])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Also works for complex numbers (and thus can be used to map any line in
							 | 
						||
| 
								 | 
							
								    the complex plane to any other line therein).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> i = complex(0,1)
							 | 
						||
| 
								 | 
							
								    >>> old = (-1 - i, 1 + i)
							 | 
						||
| 
								 | 
							
								    >>> new = (-1 + i, 1 - i)
							 | 
						||
| 
								 | 
							
								    >>> z = np.linspace(old[0], old[1], 6); z
							 | 
						||
| 
								 | 
							
								    array([-1. -1.j , -0.6-0.6j, -0.2-0.2j,  0.2+0.2j,  0.6+0.6j,  1. +1.j ])
							 | 
						||
| 
								 | 
							
								    >>> new_z = pu.mapdomain(z, old, new); new_z
							 | 
						||
| 
								 | 
							
								    array([-1.0+1.j , -0.6+0.6j, -0.2+0.2j,  0.2-0.2j,  0.6-0.6j,  1.0-1.j ]) # may vary
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    x = np.asanyarray(x)
							 | 
						||
| 
								 | 
							
								    off, scl = mapparms(old, new)
							 | 
						||
| 
								 | 
							
								    return off + scl*x
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _nth_slice(i, ndim):
							 | 
						||
| 
								 | 
							
								    sl = [np.newaxis] * ndim
							 | 
						||
| 
								 | 
							
								    sl[i] = slice(None)
							 | 
						||
| 
								 | 
							
								    return tuple(sl)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _vander_nd(vander_fs, points, degrees):
							 | 
						||
| 
								 | 
							
								    r"""
							 | 
						||
| 
								 | 
							
								    A generalization of the Vandermonde matrix for N dimensions
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The result is built by combining the results of 1d Vandermonde matrices,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. math::
							 | 
						||
| 
								 | 
							
								        W[i_0, \ldots, i_M, j_0, \ldots, j_N] = \prod_{k=0}^N{V_k(x_k)[i_0, \ldots, i_M, j_k]}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    where
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. math::
							 | 
						||
| 
								 | 
							
								        N &= \texttt{len(points)} = \texttt{len(degrees)} = \texttt{len(vander\_fs)} \\
							 | 
						||
| 
								 | 
							
								        M &= \texttt{points[k].ndim} \\
							 | 
						||
| 
								 | 
							
								        V_k &= \texttt{vander\_fs[k]} \\
							 | 
						||
| 
								 | 
							
								        x_k &= \texttt{points[k]} \\
							 | 
						||
| 
								 | 
							
								        0 \le j_k &\le \texttt{degrees[k]}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Expanding the one-dimensional :math:`V_k` functions gives:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. math::
							 | 
						||
| 
								 | 
							
								        W[i_0, \ldots, i_M, j_0, \ldots, j_N] = \prod_{k=0}^N{B_{k, j_k}(x_k[i_0, \ldots, i_M])}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    where :math:`B_{k,m}` is the m'th basis of the polynomial construction used along
							 | 
						||
| 
								 | 
							
								    dimension :math:`k`. For a regular polynomial, :math:`B_{k, m}(x) = P_m(x) = x^m`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    vander_fs : Sequence[function(array_like, int) -> ndarray]
							 | 
						||
| 
								 | 
							
								        The 1d vander function to use for each axis, such as ``polyvander``
							 | 
						||
| 
								 | 
							
								    points : Sequence[array_like]
							 | 
						||
| 
								 | 
							
								        Arrays of point coordinates, all of the same shape. The dtypes
							 | 
						||
| 
								 | 
							
								        will be converted to either float64 or complex128 depending on
							 | 
						||
| 
								 | 
							
								        whether any of the elements are complex. Scalars are converted to
							 | 
						||
| 
								 | 
							
								        1-D arrays.
							 | 
						||
| 
								 | 
							
								        This must be the same length as `vander_fs`.
							 | 
						||
| 
								 | 
							
								    degrees : Sequence[int]
							 | 
						||
| 
								 | 
							
								        The maximum degree (inclusive) to use for each axis.
							 | 
						||
| 
								 | 
							
								        This must be the same length as `vander_fs`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    vander_nd : ndarray
							 | 
						||
| 
								 | 
							
								        An array of shape ``points[0].shape + tuple(d + 1 for d in degrees)``.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    n_dims = len(vander_fs)
							 | 
						||
| 
								 | 
							
								    if n_dims != len(points):
							 | 
						||
| 
								 | 
							
								        raise ValueError(
							 | 
						||
| 
								 | 
							
								            f"Expected {n_dims} dimensions of sample points, got {len(points)}")
							 | 
						||
| 
								 | 
							
								    if n_dims != len(degrees):
							 | 
						||
| 
								 | 
							
								        raise ValueError(
							 | 
						||
| 
								 | 
							
								            f"Expected {n_dims} dimensions of degrees, got {len(degrees)}")
							 | 
						||
| 
								 | 
							
								    if n_dims == 0:
							 | 
						||
| 
								 | 
							
								        raise ValueError("Unable to guess a dtype or shape when no points are given")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # convert to the same shape and type
							 | 
						||
| 
								 | 
							
								    points = tuple(np.array(tuple(points), copy=False) + 0.0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # produce the vandermonde matrix for each dimension, placing the last
							 | 
						||
| 
								 | 
							
								    # axis of each in an independent trailing axis of the output
							 | 
						||
| 
								 | 
							
								    vander_arrays = (
							 | 
						||
| 
								 | 
							
								        vander_fs[i](points[i], degrees[i])[(...,) + _nth_slice(i, n_dims)]
							 | 
						||
| 
								 | 
							
								        for i in range(n_dims)
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # we checked this wasn't empty already, so no `initial` needed
							 | 
						||
| 
								 | 
							
								    return functools.reduce(operator.mul, vander_arrays)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _vander_nd_flat(vander_fs, points, degrees):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Like `_vander_nd`, but flattens the last ``len(degrees)`` axes into a single axis
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Used to implement the public ``<type>vander<n>d`` functions.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    v = _vander_nd(vander_fs, points, degrees)
							 | 
						||
| 
								 | 
							
								    return v.reshape(v.shape[:-len(degrees)] + (-1,))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _fromroots(line_f, mul_f, roots):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Helper function used to implement the ``<type>fromroots`` functions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    line_f : function(float, float) -> ndarray
							 | 
						||
| 
								 | 
							
								        The ``<type>line`` function, such as ``polyline``
							 | 
						||
| 
								 | 
							
								    mul_f : function(array_like, array_like) -> ndarray
							 | 
						||
| 
								 | 
							
								        The ``<type>mul`` function, such as ``polymul``
							 | 
						||
| 
								 | 
							
								    roots
							 | 
						||
| 
								 | 
							
								        See the ``<type>fromroots`` functions for more detail
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if len(roots) == 0:
							 | 
						||
| 
								 | 
							
								        return np.ones(1)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        [roots] = as_series([roots], trim=False)
							 | 
						||
| 
								 | 
							
								        roots.sort()
							 | 
						||
| 
								 | 
							
								        p = [line_f(-r, 1) for r in roots]
							 | 
						||
| 
								 | 
							
								        n = len(p)
							 | 
						||
| 
								 | 
							
								        while n > 1:
							 | 
						||
| 
								 | 
							
								            m, r = divmod(n, 2)
							 | 
						||
| 
								 | 
							
								            tmp = [mul_f(p[i], p[i+m]) for i in range(m)]
							 | 
						||
| 
								 | 
							
								            if r:
							 | 
						||
| 
								 | 
							
								                tmp[0] = mul_f(tmp[0], p[-1])
							 | 
						||
| 
								 | 
							
								            p = tmp
							 | 
						||
| 
								 | 
							
								            n = m
							 | 
						||
| 
								 | 
							
								        return p[0]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _valnd(val_f, c, *args):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Helper function used to implement the ``<type>val<n>d`` functions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    val_f : function(array_like, array_like, tensor: bool) -> array_like
							 | 
						||
| 
								 | 
							
								        The ``<type>val`` function, such as ``polyval``
							 | 
						||
| 
								 | 
							
								    c, args
							 | 
						||
| 
								 | 
							
								        See the ``<type>val<n>d`` functions for more detail
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    args = [np.asanyarray(a) for a in args]
							 | 
						||
| 
								 | 
							
								    shape0 = args[0].shape
							 | 
						||
| 
								 | 
							
								    if not all((a.shape == shape0 for a in args[1:])):
							 | 
						||
| 
								 | 
							
								        if len(args) == 3:
							 | 
						||
| 
								 | 
							
								            raise ValueError('x, y, z are incompatible')
							 | 
						||
| 
								 | 
							
								        elif len(args) == 2:
							 | 
						||
| 
								 | 
							
								            raise ValueError('x, y are incompatible')
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            raise ValueError('ordinates are incompatible')
							 | 
						||
| 
								 | 
							
								    it = iter(args)
							 | 
						||
| 
								 | 
							
								    x0 = next(it)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # use tensor on only the first
							 | 
						||
| 
								 | 
							
								    c = val_f(x0, c)
							 | 
						||
| 
								 | 
							
								    for xi in it:
							 | 
						||
| 
								 | 
							
								        c = val_f(xi, c, tensor=False)
							 | 
						||
| 
								 | 
							
								    return c
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _gridnd(val_f, c, *args):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Helper function used to implement the ``<type>grid<n>d`` functions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    val_f : function(array_like, array_like, tensor: bool) -> array_like
							 | 
						||
| 
								 | 
							
								        The ``<type>val`` function, such as ``polyval``
							 | 
						||
| 
								 | 
							
								    c, args
							 | 
						||
| 
								 | 
							
								        See the ``<type>grid<n>d`` functions for more detail
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    for xi in args:
							 | 
						||
| 
								 | 
							
								        c = val_f(xi, c)
							 | 
						||
| 
								 | 
							
								    return c
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _div(mul_f, c1, c2):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Helper function used to implement the ``<type>div`` functions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Implementation uses repeated subtraction of c2 multiplied by the nth basis.
							 | 
						||
| 
								 | 
							
								    For some polynomial types, a more efficient approach may be possible.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    mul_f : function(array_like, array_like) -> array_like
							 | 
						||
| 
								 | 
							
								        The ``<type>mul`` function, such as ``polymul``
							 | 
						||
| 
								 | 
							
								    c1, c2
							 | 
						||
| 
								 | 
							
								        See the ``<type>div`` functions for more detail
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    # c1, c2 are trimmed copies
							 | 
						||
| 
								 | 
							
								    [c1, c2] = as_series([c1, c2])
							 | 
						||
| 
								 | 
							
								    if c2[-1] == 0:
							 | 
						||
| 
								 | 
							
								        raise ZeroDivisionError()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    lc1 = len(c1)
							 | 
						||
| 
								 | 
							
								    lc2 = len(c2)
							 | 
						||
| 
								 | 
							
								    if lc1 < lc2:
							 | 
						||
| 
								 | 
							
								        return c1[:1]*0, c1
							 | 
						||
| 
								 | 
							
								    elif lc2 == 1:
							 | 
						||
| 
								 | 
							
								        return c1/c2[-1], c1[:1]*0
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        quo = np.empty(lc1 - lc2 + 1, dtype=c1.dtype)
							 | 
						||
| 
								 | 
							
								        rem = c1
							 | 
						||
| 
								 | 
							
								        for i in range(lc1 - lc2, - 1, -1):
							 | 
						||
| 
								 | 
							
								            p = mul_f([0]*i + [1], c2)
							 | 
						||
| 
								 | 
							
								            q = rem[-1]/p[-1]
							 | 
						||
| 
								 | 
							
								            rem = rem[:-1] - q*p[:-1]
							 | 
						||
| 
								 | 
							
								            quo[i] = q
							 | 
						||
| 
								 | 
							
								        return quo, trimseq(rem)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _add(c1, c2):
							 | 
						||
| 
								 | 
							
								    """ Helper function used to implement the ``<type>add`` functions. """
							 | 
						||
| 
								 | 
							
								    # c1, c2 are trimmed copies
							 | 
						||
| 
								 | 
							
								    [c1, c2] = as_series([c1, c2])
							 | 
						||
| 
								 | 
							
								    if len(c1) > len(c2):
							 | 
						||
| 
								 | 
							
								        c1[:c2.size] += c2
							 | 
						||
| 
								 | 
							
								        ret = c1
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        c2[:c1.size] += c1
							 | 
						||
| 
								 | 
							
								        ret = c2
							 | 
						||
| 
								 | 
							
								    return trimseq(ret)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _sub(c1, c2):
							 | 
						||
| 
								 | 
							
								    """ Helper function used to implement the ``<type>sub`` functions. """
							 | 
						||
| 
								 | 
							
								    # c1, c2 are trimmed copies
							 | 
						||
| 
								 | 
							
								    [c1, c2] = as_series([c1, c2])
							 | 
						||
| 
								 | 
							
								    if len(c1) > len(c2):
							 | 
						||
| 
								 | 
							
								        c1[:c2.size] -= c2
							 | 
						||
| 
								 | 
							
								        ret = c1
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        c2 = -c2
							 | 
						||
| 
								 | 
							
								        c2[:c1.size] += c1
							 | 
						||
| 
								 | 
							
								        ret = c2
							 | 
						||
| 
								 | 
							
								    return trimseq(ret)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _fit(vander_f, x, y, deg, rcond=None, full=False, w=None):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Helper function used to implement the ``<type>fit`` functions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    vander_f : function(array_like, int) -> ndarray
							 | 
						||
| 
								 | 
							
								        The 1d vander function, such as ``polyvander``
							 | 
						||
| 
								 | 
							
								    c1, c2
							 | 
						||
| 
								 | 
							
								        See the ``<type>fit`` functions for more detail
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    x = np.asarray(x) + 0.0
							 | 
						||
| 
								 | 
							
								    y = np.asarray(y) + 0.0
							 | 
						||
| 
								 | 
							
								    deg = np.asarray(deg)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # check arguments.
							 | 
						||
| 
								 | 
							
								    if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0:
							 | 
						||
| 
								 | 
							
								        raise TypeError("deg must be an int or non-empty 1-D array of int")
							 | 
						||
| 
								 | 
							
								    if deg.min() < 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 len(x) != len(y):
							 | 
						||
| 
								 | 
							
								        raise TypeError("expected x and y to have same length")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if deg.ndim == 0:
							 | 
						||
| 
								 | 
							
								        lmax = deg
							 | 
						||
| 
								 | 
							
								        order = lmax + 1
							 | 
						||
| 
								 | 
							
								        van = vander_f(x, lmax)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        deg = np.sort(deg)
							 | 
						||
| 
								 | 
							
								        lmax = deg[-1]
							 | 
						||
| 
								 | 
							
								        order = len(deg)
							 | 
						||
| 
								 | 
							
								        van = vander_f(x, lmax)[:, deg]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # set up the least squares matrices in transposed form
							 | 
						||
| 
								 | 
							
								    lhs = van.T
							 | 
						||
| 
								 | 
							
								    rhs = y.T
							 | 
						||
| 
								 | 
							
								    if w is not None:
							 | 
						||
| 
								 | 
							
								        w = np.asarray(w) + 0.0
							 | 
						||
| 
								 | 
							
								        if w.ndim != 1:
							 | 
						||
| 
								 | 
							
								            raise TypeError("expected 1D vector for w")
							 | 
						||
| 
								 | 
							
								        if len(x) != len(w):
							 | 
						||
| 
								 | 
							
								            raise TypeError("expected x and w to have same length")
							 | 
						||
| 
								 | 
							
								        # apply weights. Don't use inplace operations as they
							 | 
						||
| 
								 | 
							
								        # can cause problems with NA.
							 | 
						||
| 
								 | 
							
								        lhs = lhs * w
							 | 
						||
| 
								 | 
							
								        rhs = rhs * w
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # set rcond
							 | 
						||
| 
								 | 
							
								    if rcond is None:
							 | 
						||
| 
								 | 
							
								        rcond = len(x)*np.finfo(x.dtype).eps
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Determine the norms of the design matrix columns.
							 | 
						||
| 
								 | 
							
								    if issubclass(lhs.dtype.type, np.complexfloating):
							 | 
						||
| 
								 | 
							
								        scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1))
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        scl = np.sqrt(np.square(lhs).sum(1))
							 | 
						||
| 
								 | 
							
								    scl[scl == 0] = 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Solve the least squares problem.
							 | 
						||
| 
								 | 
							
								    c, resids, rank, s = np.linalg.lstsq(lhs.T/scl, rhs.T, rcond)
							 | 
						||
| 
								 | 
							
								    c = (c.T/scl).T
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Expand c to include non-fitted coefficients which are set to zero
							 | 
						||
| 
								 | 
							
								    if deg.ndim > 0:
							 | 
						||
| 
								 | 
							
								        if c.ndim == 2:
							 | 
						||
| 
								 | 
							
								            cc = np.zeros((lmax+1, c.shape[1]), dtype=c.dtype)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            cc = np.zeros(lmax+1, dtype=c.dtype)
							 | 
						||
| 
								 | 
							
								        cc[deg] = c
							 | 
						||
| 
								 | 
							
								        c = cc
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # warn on rank reduction
							 | 
						||
| 
								 | 
							
								    if rank != order and not full:
							 | 
						||
| 
								 | 
							
								        msg = "The fit may be poorly conditioned"
							 | 
						||
| 
								 | 
							
								        warnings.warn(msg, RankWarning, stacklevel=2)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if full:
							 | 
						||
| 
								 | 
							
								        return c, [resids, rank, s, rcond]
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return c
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _pow(mul_f, c, pow, maxpower):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Helper function used to implement the ``<type>pow`` functions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    mul_f : function(array_like, array_like) -> ndarray
							 | 
						||
| 
								 | 
							
								        The ``<type>mul`` function, such as ``polymul``
							 | 
						||
| 
								 | 
							
								    c : array_like
							 | 
						||
| 
								 | 
							
								        1-D array of array of series coefficients
							 | 
						||
| 
								 | 
							
								    pow, maxpower
							 | 
						||
| 
								 | 
							
								        See the ``<type>pow`` functions for more detail
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    # c is a trimmed copy
							 | 
						||
| 
								 | 
							
								    [c] = as_series([c])
							 | 
						||
| 
								 | 
							
								    power = int(pow)
							 | 
						||
| 
								 | 
							
								    if power != pow or power < 0:
							 | 
						||
| 
								 | 
							
								        raise ValueError("Power must be a non-negative integer.")
							 | 
						||
| 
								 | 
							
								    elif maxpower is not None and power > maxpower:
							 | 
						||
| 
								 | 
							
								        raise ValueError("Power is too large")
							 | 
						||
| 
								 | 
							
								    elif power == 0:
							 | 
						||
| 
								 | 
							
								        return np.array([1], dtype=c.dtype)
							 | 
						||
| 
								 | 
							
								    elif power == 1:
							 | 
						||
| 
								 | 
							
								        return c
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        # This can be made more efficient by using powers of two
							 | 
						||
| 
								 | 
							
								        # in the usual way.
							 | 
						||
| 
								 | 
							
								        prd = c
							 | 
						||
| 
								 | 
							
								        for i in range(2, power + 1):
							 | 
						||
| 
								 | 
							
								            prd = mul_f(prd, c)
							 | 
						||
| 
								 | 
							
								        return prd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _deprecate_as_int(x, desc):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Like `operator.index`, but emits a deprecation warning when passed a float
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    x : int-like, or float with integral value
							 | 
						||
| 
								 | 
							
								        Value to interpret as an integer
							 | 
						||
| 
								 | 
							
								    desc : str
							 | 
						||
| 
								 | 
							
								        description to include in any error message
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Raises
							 | 
						||
| 
								 | 
							
								    ------
							 | 
						||
| 
								 | 
							
								    TypeError : if x is a non-integral float or non-numeric
							 | 
						||
| 
								 | 
							
								    DeprecationWarning : if x is an integral float
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        return operator.index(x)
							 | 
						||
| 
								 | 
							
								    except TypeError as e:
							 | 
						||
| 
								 | 
							
								        # Numpy 1.17.0, 2019-03-11
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            ix = int(x)
							 | 
						||
| 
								 | 
							
								        except TypeError:
							 | 
						||
| 
								 | 
							
								            pass
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            if ix == x:
							 | 
						||
| 
								 | 
							
								                warnings.warn(
							 | 
						||
| 
								 | 
							
								                    f"In future, this will raise TypeError, as {desc} will "
							 | 
						||
| 
								 | 
							
								                    "need to be an integer not just an integral float.",
							 | 
						||
| 
								 | 
							
								                    DeprecationWarning,
							 | 
						||
| 
								 | 
							
								                    stacklevel=3
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								                return ix
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        raise TypeError(f"{desc} must be an integer") from e
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def format_float(x, parens=False):
							 | 
						||
| 
								 | 
							
								    if not np.issubdtype(type(x), np.floating):
							 | 
						||
| 
								 | 
							
								        return str(x)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    opts = np.get_printoptions()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if np.isnan(x):
							 | 
						||
| 
								 | 
							
								        return opts['nanstr']
							 | 
						||
| 
								 | 
							
								    elif np.isinf(x):
							 | 
						||
| 
								 | 
							
								        return opts['infstr']
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    exp_format = False
							 | 
						||
| 
								 | 
							
								    if x != 0:
							 | 
						||
| 
								 | 
							
								        a = absolute(x)
							 | 
						||
| 
								 | 
							
								        if a >= 1.e8 or a < 10**min(0, -(opts['precision']-1)//2):
							 | 
						||
| 
								 | 
							
								            exp_format = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    trim, unique = '0', True
							 | 
						||
| 
								 | 
							
								    if opts['floatmode'] == 'fixed':
							 | 
						||
| 
								 | 
							
								        trim, unique = 'k', False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if exp_format:
							 | 
						||
| 
								 | 
							
								        s = dragon4_scientific(x, precision=opts['precision'],
							 | 
						||
| 
								 | 
							
								                               unique=unique, trim=trim, 
							 | 
						||
| 
								 | 
							
								                               sign=opts['sign'] == '+')
							 | 
						||
| 
								 | 
							
								        if parens:
							 | 
						||
| 
								 | 
							
								            s = '(' + s + ')'
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        s = dragon4_positional(x, precision=opts['precision'],
							 | 
						||
| 
								 | 
							
								                               fractional=True,
							 | 
						||
| 
								 | 
							
								                               unique=unique, trim=trim,
							 | 
						||
| 
								 | 
							
								                               sign=opts['sign'] == '+')
							 | 
						||
| 
								 | 
							
								    return s
							 |