summaryrefslogtreecommitdiff
path: root/numpy/lib/polynomial.py
diff options
context:
space:
mode:
authorStefan van der Walt <stefan@sun.ac.za>2008-08-05 09:20:07 +0000
committerStefan van der Walt <stefan@sun.ac.za>2008-08-05 09:20:07 +0000
commit6647bf7eaeb915e2d09db8b5c7584ee286962d3b (patch)
tree803c7d548fb8dc8f571aad76c6473f20ba71c01d /numpy/lib/polynomial.py
parentf8f44a0595da3ae8be9458ead1366bcc72cd3390 (diff)
downloadnumpy-6647bf7eaeb915e2d09db8b5c7584ee286962d3b.tar.gz
Merge from documentation editor.
Diffstat (limited to 'numpy/lib/polynomial.py')
-rw-r--r--numpy/lib/polynomial.py540
1 files changed, 412 insertions, 128 deletions
diff --git a/numpy/lib/polynomial.py b/numpy/lib/polynomial.py
index 8fb0337dc..bce7f0e4e 100644
--- a/numpy/lib/polynomial.py
+++ b/numpy/lib/polynomial.py
@@ -46,15 +46,49 @@ def _lstsq(X, y, rcond):
return lstsq(X, y, rcond)
def poly(seq_of_zeros):
- """ Return a sequence representing a polynomial given a sequence of roots.
+ """
+ Return polynomial coefficients given a sequence of roots.
+
+ Calculate the coefficients of a polynomial given the zeros
+ of the polynomial.
+
+ If a square matrix is given, then the coefficients for
+ characteristic equation of the matrix, defined by
+ :math:`\\mathrm{det}(\\mathbf{A} - \\lambda \\mathbf{I})`,
+ are returned.
+
+ Parameters
+ ----------
+ seq_of_zeros : ndarray
+ A sequence of polynomial roots or a square matrix.
+
+ Returns
+ -------
+ coefs : ndarray
+ A sequence of polynomial coefficients representing the polynomial
+
+ :math:`\\mathrm{coefs}[0] x^{n-1} + \\mathrm{coefs}[1] x^{n-2} +
+ ... + \\mathrm{coefs}[2] x + \\mathrm{coefs}[n]`
+
+ See Also
+ --------
+ numpy.poly1d : A one-dimensional polynomial class.
+ numpy.roots : Return the roots of the polynomial coefficients in p
+ numpy.polyfit : Least squares polynomial fit
+
+ Examples
+ --------
+ Given a sequence of polynomial zeros,
- If the input is a matrix, return the characteristic polynomial.
+ >>> b = np.roots([1, 3, 1, 5, 6])
+ >>> np.poly(b)
+ array([ 1., 3., 1., 5., 6.])
- Example:
+ Given a square matrix,
- >>> b = np.roots([1,3,1,5,6])
- >>> np.poly(b)
- array([ 1., 3., 1., 5., 6.])
+ >>> P = np.array([[19, 3], [-2, 26]])
+ >>> np.poly(P)
+ array([ 1., -45., 500.])
"""
seq_of_zeros = atleast_1d(seq_of_zeros)
@@ -86,11 +120,35 @@ def poly(seq_of_zeros):
return a
def roots(p):
- """ Return the roots of the polynomial coefficients in p.
+ """
+ Return the roots of a polynomial with coefficients given in p.
+
+ 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 : (N,) array_like
+ Rank-1 array of polynomial co-efficients.
+
+ Returns
+ -------
+ out : ndarray
+ An array containing the complex roots of the polynomial.
+
+ Raises
+ ------
+ ValueError:
+ When `p` cannot be converted to a rank-1 array.
+
+ Examples
+ --------
+
+ >>> coeff = [3.2, 2, 1]
+ >>> print np.roots(coeff)
+ [-0.3125+0.46351241j -0.3125-0.46351241j]
- 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
- p[0] * x**n + p[1] * x**(n-1) + ... + p[n-1]*x + p[n]
"""
# If input is scalar, this makes it an array
p = atleast_1d(p)
@@ -128,12 +186,70 @@ def roots(p):
return roots
def polyint(p, m=1, k=None):
- """Return the mth analytical integral of the polynomial p.
+ """
+ Return an antiderivative (indefinite integral) of a polynomial.
+
+ 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 : poly1d or sequence
+ Polynomial to differentiate.
+ A sequence is interpreted as polynomial coefficients, see `poly1d`.
+ m : int, optional
+ Order of the antiderivative. (Default: 1)
+ k : {None, list of `m` scalars, 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:
+
+ >>> p = np.poly1d([1,1,1])
+ >>> P = np.polyint(p)
+ poly1d([ 0.33333333, 0.5 , 1. , 0. ])
+ >>> 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. ])
+
+ 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
- If k is None, then zero-valued constants of integration are used.
- otherwise, k should be a list of length m (or a scalar if m=1) to
- represent the constants of integration to use for each integration
- (starting with k[0])
"""
m = int(m)
if m < 0:
@@ -160,7 +276,55 @@ def polyint(p, m=1, k=None):
return val
def polyder(p, m=1):
- """Return the mth derivative of the polynomial p.
+ """
+ Return the derivative of order m of a polynomial.
+
+ 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.
+
+ Examples
+ --------
+ The derivative of the polynomial :math:`x^3 + x^2 + x^1 + 1` is:
+
+ >>> 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)
truepoly = isinstance(p, poly1d)
@@ -178,107 +342,134 @@ def polyder(p, m=1):
return val
def polyfit(x, y, deg, rcond=None, full=False):
- """Least squares polynomial fit.
-
- Do a best fit polynomial of degree 'deg' of 'x' to 'y'. Return value is a
- vector of polynomial coefficients [pk ... p1 p0]. Eg, for n=2
+ """
+ Least squares polynomial fit.
- p2*x0^2 + p1*x0 + p0 = y1
- p2*x1^2 + p1*x1 + p0 = y1
- p2*x2^2 + p1*x2 + p0 = y2
- .....
- p2*xk^2 + p1*xk + p0 = yk
+ 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.
Parameters
----------
- x : array_like
- 1D vector of sample points.
- y : array_like
- 1D vector or 2D array of values to fit. The values should run down the
- columes in the 2D case.
- deg : integer
+ 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: {None, float}, optional
+ rcond : float, optional
Relative condition number of the fit. Singular values smaller than this
- relative to the largest singular value will be ignored. The defaul value
- is len(x)*eps, where eps is the relative precision of the float type,
- about 2e-16 in most cases.
- full : {False, boolean}, optional
- Switch determining nature of return value. When it is False just the
- coefficients are returned, when True diagnostic information from the
- singular value decomposition is also returned.
+ 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.
Returns
-------
- coefficients, [residuals, rank, singular_values, rcond] : variable
- When full=False, only the coefficients are returned, running down the
- appropriate colume when y is a 2D array. When full=True, the rank of the
- scaled Vandermonde matrix, it's effective rank in light of the rcond
- value, its singular values, and the specified value of rcond are also
- returned.
+ p : ndarray, shape (M,) or (M, 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 : present only if `full` = True
+ Residuals of the least-squares fit, the effective rank of the scaled
+ Vandermonde coefficient matrix, its singular values, and the specified
+ value of `rcond`. For more details, see `linalg.lstsq`.
Warns
-----
- RankWarning : if rank is reduced and not full output
- The warnings can be turned off by:
- >>> import warnings
- >>> warnings.simplefilter('ignore',np.RankWarning)
+ 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.RankWarning)
See Also
--------
- polyval : computes polynomial values.
+ polyval : Computes polynomial values.
+ linalg.lstsq : Computes a least-squares fit.
+ scipy.interpolate.UnivariateSpline : Computes spline fits.
Notes
-----
- If X is a the Vandermonde Matrix computed from x (see
- http://mathworld.wolfram.com/VandermondeMatrix.html), then the
- polynomial least squares solution is given by the 'p' in
-
- X*p = y
-
- where X.shape is a matrix of dimensions (len(x), deg + 1), p is a vector of
- dimensions (deg + 1, 1), and y is a vector of dimensions (len(x), 1).
-
- This equation can be solved as
-
- p = (XT*X)^-1 * XT * y
-
- where XT is the transpose of X and -1 denotes the inverse. However, this
- method is susceptible to rounding errors and generally the singular value
- decomposition of the matrix X is preferred and that is what is done here.
- The singular value method takes a paramenter, 'rcond', which sets a limit on
- the relative size of the smallest singular value to be used in solving the
- equation. This may result in lowering the rank of the Vandermonde matrix, in
- which case a RankWarning is issued. If polyfit issues a RankWarning, try a
- fit of lower degree or replace x by x - x.mean(), both of which will
- generally improve the condition number. The routine already normalizes the
- vector x by its maximum absolute value to help in this regard. The rcond
- parameter can be set to a value smaller than its default, but the resulting
- fit may be spurious. The current default value of rcond is len(x)*eps, where
- eps is the relative precision of the floating type being used, generally
- around 1e-7 and 2e-16 for IEEE single and double precision respectively.
- This value of rcond is fairly conservative but works pretty well when x -
- x.mean() is used in place of x.
-
-
- DISCLAIMER: Power series fits are full of pitfalls for the unwary once the
- degree of the fit becomes large or the interval of sample points is badly
- centered. The problem is that the powers x**n are generally a poor basis for
- the polynomial functions on the sample interval, resulting in a Vandermonde
- matrix is ill conditioned and coefficients sensitive to rounding erros. The
- computation of the polynomial values will also sensitive to rounding errors.
- Consequently, the quality of the polynomial fit should be checked against
- the data whenever the condition number is large. The quality of polynomial
- fits *can not* be taken for granted. If all you want to do is draw a smooth
- curve through the y values and polyfit is not doing the job, try centering
- the sample range or look into scipy.interpolate, which includes some nice
- spline fitting functions that may be of use.
-
- For more info, see
- http://mathworld.wolfram.com/LeastSquaresFittingPolynomial.html,
- but note that the k's and n's in the superscripts and subscripts
- on that page. The linear algebra is correct, however.
+ 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[n] + ... + x[0] * p[1] + p[0] = y[0]
+ x[1]**n * p[n] + ... + x[1] * p[1] + p[0] = y[1]
+ ...
+ x[k]**n * p[n] + ... + x[k] * p[1] + p[0] = y[k]
+
+ The coefficient matrix of the coefficients `p` is a Vandermonde matrix.
+
+ `polyfit` issues a `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",
+ http://en.wikipedia.org/wiki/Curve_fitting
+ .. [2] Wikipedia, "Polynomial interpolation",
+ http://en.wikipedia.org/wiki/Polynomial_interpolation
+
+ Examples
+ --------
+ >>> 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)
+ array([ 0.08703704, -0.81349206, 1.69312169, -0.03968254])
+
+ It is convenient to use `poly1d` objects for dealing with polynomials:
+
+ >>> p = np.poly1d(z)
+ >>> p(0.5)
+ 0.6143849206349179
+ >>> p(3.5)
+ -0.34732142857143039
+ >>> p(10)
+ 22.579365079365115
+
+ High-order polynomials may oscillate wildly:
+
+ >>> p30 = np.poly1d(np.polyfit(x, y, 30))
+ /... RankWarning: Polyfit may be poorly conditioned...
+ >>> p30(4)
+ -0.80000000000000204
+ >>> p30(5)
+ -0.99999999999999445
+ >>> p30(4.5)
+ -0.10547061179440398
+
+ 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)
+ >>> plt.show()
"""
order = int(deg) + 1
@@ -330,36 +521,48 @@ def polyfit(x, y, deg, rcond=None, full=False):
def polyval(p, x):
- """Evaluate the polynomial p at x.
+ """
+ Evaluate the polynomial p at x.
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) will be returned for all elements of x. If x is
- another polynomial then the composite polynomial p(x) will be returned.
+ If x is a sequence then p(x) will be returned for all elements of x.
+ If x is another polynomial then the composite polynomial p(x) will
+ be returned.
Parameters
----------
p : {array_like, poly1d}
- 1D array of polynomial coefficients from highest degree to zero or an
- instance of poly1d.
+ 1D array of polynomial coefficients from highest degree to zero or an
+ instance of poly1d.
x : {array_like, poly1d}
- A number, a 1D array of numbers, or an instance of poly1d.
+ A number, a 1D array of numbers, or an instance of poly1d.
Returns
-------
values : {array, poly1d}
- If either p or x is an instance of poly1d, then an instance of poly1d is
- returned, otherwise a 1D array is returned. In the case where x is a
- poly1d, the result is the composition of the two polynomials, i.e.,
- substitution is used.
+ If either p or x is an instance of poly1d, then an instance of poly1d
+ is returned, otherwise a 1D array is returned. In the case where x is
+ a poly1d, the result is the composition of the two polynomials, i.e.,
+ substitution is used.
+
+ See Also
+ --------
+ poly1d: A polynomial class.
Notes
-----
- Horners method is used to evaluate the polynomial. Even so, for polynomial
- if high degree the values may be inaccurate due to rounding errors. Use
- carefully.
+ Horner's method is used to evaluate the polynomial. Even so, for
+ polynomials of high degree the values may be inaccurate due to
+ rounding errors. Use carefully.
+
+
+ Examples
+ --------
+ >>> np.polyval([3,0,1], 5) # 3 * 5**2 + 0 * 5**1 + 1
+ 76
"""
p = NX.asarray(p)
@@ -473,24 +676,90 @@ def _raise_power(astr, wrap=70):
class poly1d(object):
- """A one-dimensional polynomial class.
+ """
+ A one-dimensional polynomial class.
+
+ Parameters
+ ----------
+ c_or_r : array_like
+ Polynomial coefficients, in decreasing powers. E.g.,
+ ``(1, 2, 3)`` implies :math:`x^2 + 2x + 3`. If `r` is set
+ to True, these coefficients specify the polynomial roots
+ (values where the polynomial evaluate to 0) instead.
+ r : bool, optional
+ If True, `c_or_r` gives the polynomial roots. Default is False.
+
+ Examples
+ --------
+ Construct the polynomial :math:`x^2 + 2x + 3`:
+
+ >>> p = np.poly1d([1, 2, 3])
+ >>> print np.poly1d(p)
+ 2
+ 1 x + 2 x + 3
+
+ Evaluate the polynomial:
+
+ >>> p(0.5)
+ 4.25
+
+ Find the roots:
+
+ >>> p.r
+ array([-1.+1.41421356j, -1.-1.41421356j])
+
+ 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, substracted, multplied 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]))
- p = poly1d([1,2,3]) constructs the polynomial x**2 + 2 x + 3
+ ``asarray(p)`` gives the coefficient array, so polynomials can be
+ used in all functions that accept arrays:
- p(0.5) evaluates the polynomial at the location
- p.r is a list of roots
- p.c is the coefficient array [1,2,3]
- p.order is the polynomial order (after leading zeros in p.c are removed)
- p[k] is the coefficient on the kth power of x (backwards from
- sequencing the coefficient array.
+ >>> p**2 # square of polynomial
+ poly1d([ 1, 4, 10, 12, 9])
- polynomials can be added, substracted, multplied and divided (returns
- quotient and remainder).
- asarray(p) will also give the coefficient array, so polynomials can
- be used in all functions that accept arrays.
+ >>> 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])
- p = poly1d([1,2,3], variable='lambda') will use lambda in the
- string representation of p.
"""
coeffs = None
order = None
@@ -686,13 +955,28 @@ class poly1d(object):
return iter(self.coeffs)
def integ(self, m=1, k=0):
- """Return the mth analytical integral of this polynomial.
- See the documentation for polyint.
+ """
+ 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 the mth derivative of this polynomial.
+ """
+ Return a derivative of this polynomial.
+
+ Refer to `polyder` for full documentation.
+
+ See Also
+ --------
+ polyder : equivalent function
+
"""
return poly1d(polyder(self.coeffs, m=m))