summaryrefslogtreecommitdiff
path: root/numpy/polynomial/polynomial.py
diff options
context:
space:
mode:
authore-q <eric.antonio.quintero@gmail.com>2016-04-12 11:26:05 -0700
committerCharles Harris <charlesr.harris@gmail.com>2016-06-12 12:08:54 -0600
commit76e2d4751294077cc4cafe155571ead8213133a8 (patch)
tree3a449a0337c637f1983a7570a3347ccfdaa7c347 /numpy/polynomial/polynomial.py
parent76c27b5d2a28657062b2dcebba062f1941e4955f (diff)
downloadnumpy-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.py92
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).