diff options
author | e-q <eric.antonio.quintero@gmail.com> | 2016-04-12 11:26:05 -0700 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2016-06-12 12:08:54 -0600 |
commit | 76e2d4751294077cc4cafe155571ead8213133a8 (patch) | |
tree | 3a449a0337c637f1983a7570a3347ccfdaa7c347 /numpy/polynomial/polynomial.py | |
parent | 76c27b5d2a28657062b2dcebba062f1941e4955f (diff) | |
download | numpy-76e2d4751294077cc4cafe155571ead8213133a8.tar.gz |
ENH: Add `polyrootval` to numpy.polynomial
As one can easily encounter when working with high-order signal processing
filters, converting a high-order polynomial from its roots to its polynomial
coefficients can be quite lossy, leading to inaccuracies in the filter's
properties.
This PR adds a new function, `polyrootval` - based on `polyval` - that
evaluates a polynomial given a list of its roots. The benefit of calculating it
this way can be seen at scipy/scipy:6059. Some tests are included, as well.
Diffstat (limited to 'numpy/polynomial/polynomial.py')
-rw-r--r-- | numpy/polynomial/polynomial.py | 92 |
1 files changed, 90 insertions, 2 deletions
diff --git a/numpy/polynomial/polynomial.py b/numpy/polynomial/polynomial.py index 5d05f5991..23f1f6a36 100644 --- a/numpy/polynomial/polynomial.py +++ b/numpy/polynomial/polynomial.py @@ -36,6 +36,7 @@ Misc Functions -------------- - `polyfromroots` -- create a polynomial with specified roots. - `polyroots` -- find the roots of a polynomial. +- `polyvalfromroots` -- evalute a polynomial at given points from roots. - `polyvander` -- Vandermonde-like matrix for powers. - `polyvander2d` -- Vandermonde-like matrix for 2D power series. - `polyvander3d` -- Vandermonde-like matrix for 3D power series. @@ -58,8 +59,8 @@ from __future__ import division, absolute_import, print_function __all__ = [ 'polyzero', 'polyone', 'polyx', 'polydomain', 'polyline', 'polyadd', 'polysub', 'polymulx', 'polymul', 'polydiv', 'polypow', 'polyval', - 'polyder', 'polyint', 'polyfromroots', 'polyvander', 'polyfit', - 'polytrim', 'polyroots', 'Polynomial', 'polyval2d', 'polyval3d', + 'polyvalfromroots', 'polyder', 'polyint', 'polyfromroots', 'polyvander', + 'polyfit', 'polytrim', 'polyroots', 'Polynomial', 'polyval2d', 'polyval3d', 'polygrid2d', 'polygrid3d', 'polyvander2d', 'polyvander3d'] import warnings @@ -780,6 +781,93 @@ def polyval(x, c, tensor=True): return c0 +def polyvalfromroots(x, r, tensor=True): + """ + Evaluate a polynomial specified by its roots at points x. + + If `r` is of length `N`, this function returns the value + + .. math:: p(x) = \prod_{n=1}^{N} (x - r_n) + + The parameter `x` is converted to an array only if it is a tuple or a + list, otherwise it is treated as a scalar. In either case, either `x` + or its elements must support multiplication and addition both with + themselves and with the elements of `r`. + + If `r` is a 1-D array, then `p(x)` will have the same shape as `x`. If `r` + is multidimensional, then the shape of the result depends on the value of + `tensor`. If `tensor is ``True`` the shape will be r.shape[1:] + x.shape; + that is, each polynomial is evaluated at every value of `x`. If `tensor` is + ``False``, the shape will be r.shape[1:]; that is, each polynomial is + evaluated only for the corresponding broadcast value of `x`. Note that + scalars have shape (,). + + .. versionadded:: 1.12 + + Parameters + ---------- + x : array_like, compatible object + If `x` is a list or tuple, it is converted to an ndarray, otherwise + it is left unchanged and treated as a scalar. In either case, `x` + or its elements must support addition and multiplication with + with themselves and with the elements of `r`. + r : array_like + Array of roots. If `r` is multidimensional the first index is the + root index, while the remaining indices enumerate multiple + polynomials. For instance, in the two dimensional case the roots + of each polynomial may be thought of as stored in the columns of `r`. + tensor : boolean, optional + If True, the shape of the roots array is extended with ones on the + right, one for each dimension of `x`. Scalars have dimension 0 for this + action. The result is that every column of coefficients in `r` is + evaluated for every element of `x`. If False, `x` is broadcast over the + columns of `r` for the evaluation. This keyword is useful when `r` is + multidimensional. The default value is True. + + Returns + ------- + values : ndarray, compatible object + The shape of the returned array is described above. + + See Also + -------- + polyroots, polyfromroots, polyval + + Examples + -------- + >>> from numpy.polynomial.polynomial import polyvalfromroots + >>> polyvalfromroots(1, [1,2,3]) + 0.0 + >>> a = np.arange(4).reshape(2,2) + >>> a + array([[0, 1], + [2, 3]]) + >>> polyvalfromroots(a, [-1, 0, 1]) + array([[ -0., 0.], + [ 6., 24.]]) + >>> r = np.arange(-2, 2).reshape(2,2) # multidimensional coefficients + >>> r # each column of r defines one polynomial + array([[-2, -1], + [ 0, 1]]) + >>> b = [-2, 1] + >>> polyvalfromroots(b, r, tensor=True) + array([[-0., 3.], + [ 3., 0.]]) + >>> polyvalfromroots(b, r, tensor=False) + array([-0., 0.]) + """ + r = np.array(r, ndmin=1, copy=0) + 0.0 + if r.size == 0: + return np.ones_like(x) + if np.isscalar(x) or isinstance(x, (tuple, list)): + x = np.array(x, ndmin=1, copy=0) + 0.0 + if isinstance(x, np.ndarray) and tensor: + if x.size == 0: + return x.reshape(r.shape[1:]+x.shape) + r = r.reshape(r.shape + (1,)*x.ndim) + return np.prod(x - r, axis=0) + + def polyval2d(x, y, c): """ Evaluate a 2-D polynomial at points (x, y). |