annotate DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/lib/polynomial.py @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2a2c65a20a8b
children
rev   line source
Chris@87 1 """
Chris@87 2 Functions to operate on polynomials.
Chris@87 3
Chris@87 4 """
Chris@87 5 from __future__ import division, absolute_import, print_function
Chris@87 6
Chris@87 7 __all__ = ['poly', 'roots', 'polyint', 'polyder', 'polyadd',
Chris@87 8 'polysub', 'polymul', 'polydiv', 'polyval', 'poly1d',
Chris@87 9 'polyfit', 'RankWarning']
Chris@87 10
Chris@87 11 import re
Chris@87 12 import warnings
Chris@87 13 import numpy.core.numeric as NX
Chris@87 14
Chris@87 15 from numpy.core import isscalar, abs, finfo, atleast_1d, hstack, dot
Chris@87 16 from numpy.lib.twodim_base import diag, vander
Chris@87 17 from numpy.lib.function_base import trim_zeros, sort_complex
Chris@87 18 from numpy.lib.type_check import iscomplex, real, imag
Chris@87 19 from numpy.linalg import eigvals, lstsq, inv
Chris@87 20
Chris@87 21 class RankWarning(UserWarning):
Chris@87 22 """
Chris@87 23 Issued by `polyfit` when the Vandermonde matrix is rank deficient.
Chris@87 24
Chris@87 25 For more information, a way to suppress the warning, and an example of
Chris@87 26 `RankWarning` being issued, see `polyfit`.
Chris@87 27
Chris@87 28 """
Chris@87 29 pass
Chris@87 30
Chris@87 31 def poly(seq_of_zeros):
Chris@87 32 """
Chris@87 33 Find the coefficients of a polynomial with the given sequence of roots.
Chris@87 34
Chris@87 35 Returns the coefficients of the polynomial whose leading coefficient
Chris@87 36 is one for the given sequence of zeros (multiple roots must be included
Chris@87 37 in the sequence as many times as their multiplicity; see Examples).
Chris@87 38 A square matrix (or array, which will be treated as a matrix) can also
Chris@87 39 be given, in which case the coefficients of the characteristic polynomial
Chris@87 40 of the matrix are returned.
Chris@87 41
Chris@87 42 Parameters
Chris@87 43 ----------
Chris@87 44 seq_of_zeros : array_like, shape (N,) or (N, N)
Chris@87 45 A sequence of polynomial roots, or a square array or matrix object.
Chris@87 46
Chris@87 47 Returns
Chris@87 48 -------
Chris@87 49 c : ndarray
Chris@87 50 1D array of polynomial coefficients from highest to lowest degree:
Chris@87 51
Chris@87 52 ``c[0] * x**(N) + c[1] * x**(N-1) + ... + c[N-1] * x + c[N]``
Chris@87 53 where c[0] always equals 1.
Chris@87 54
Chris@87 55 Raises
Chris@87 56 ------
Chris@87 57 ValueError
Chris@87 58 If input is the wrong shape (the input must be a 1-D or square
Chris@87 59 2-D array).
Chris@87 60
Chris@87 61 See Also
Chris@87 62 --------
Chris@87 63 polyval : Evaluate a polynomial at a point.
Chris@87 64 roots : Return the roots of a polynomial.
Chris@87 65 polyfit : Least squares polynomial fit.
Chris@87 66 poly1d : A one-dimensional polynomial class.
Chris@87 67
Chris@87 68 Notes
Chris@87 69 -----
Chris@87 70 Specifying the roots of a polynomial still leaves one degree of
Chris@87 71 freedom, typically represented by an undetermined leading
Chris@87 72 coefficient. [1]_ In the case of this function, that coefficient -
Chris@87 73 the first one in the returned array - is always taken as one. (If
Chris@87 74 for some reason you have one other point, the only automatic way
Chris@87 75 presently to leverage that information is to use ``polyfit``.)
Chris@87 76
Chris@87 77 The characteristic polynomial, :math:`p_a(t)`, of an `n`-by-`n`
Chris@87 78 matrix **A** is given by
Chris@87 79
Chris@87 80 :math:`p_a(t) = \\mathrm{det}(t\\, \\mathbf{I} - \\mathbf{A})`,
Chris@87 81
Chris@87 82 where **I** is the `n`-by-`n` identity matrix. [2]_
Chris@87 83
Chris@87 84 References
Chris@87 85 ----------
Chris@87 86 .. [1] M. Sullivan and M. Sullivan, III, "Algebra and Trignometry,
Chris@87 87 Enhanced With Graphing Utilities," Prentice-Hall, pg. 318, 1996.
Chris@87 88
Chris@87 89 .. [2] G. Strang, "Linear Algebra and Its Applications, 2nd Edition,"
Chris@87 90 Academic Press, pg. 182, 1980.
Chris@87 91
Chris@87 92 Examples
Chris@87 93 --------
Chris@87 94 Given a sequence of a polynomial's zeros:
Chris@87 95
Chris@87 96 >>> np.poly((0, 0, 0)) # Multiple root example
Chris@87 97 array([1, 0, 0, 0])
Chris@87 98
Chris@87 99 The line above represents z**3 + 0*z**2 + 0*z + 0.
Chris@87 100
Chris@87 101 >>> np.poly((-1./2, 0, 1./2))
Chris@87 102 array([ 1. , 0. , -0.25, 0. ])
Chris@87 103
Chris@87 104 The line above represents z**3 - z/4
Chris@87 105
Chris@87 106 >>> np.poly((np.random.random(1.)[0], 0, np.random.random(1.)[0]))
Chris@87 107 array([ 1. , -0.77086955, 0.08618131, 0. ]) #random
Chris@87 108
Chris@87 109 Given a square array object:
Chris@87 110
Chris@87 111 >>> P = np.array([[0, 1./3], [-1./2, 0]])
Chris@87 112 >>> np.poly(P)
Chris@87 113 array([ 1. , 0. , 0.16666667])
Chris@87 114
Chris@87 115 Or a square matrix object:
Chris@87 116
Chris@87 117 >>> np.poly(np.matrix(P))
Chris@87 118 array([ 1. , 0. , 0.16666667])
Chris@87 119
Chris@87 120 Note how in all cases the leading coefficient is always 1.
Chris@87 121
Chris@87 122 """
Chris@87 123 seq_of_zeros = atleast_1d(seq_of_zeros)
Chris@87 124 sh = seq_of_zeros.shape
Chris@87 125 if len(sh) == 2 and sh[0] == sh[1] and sh[0] != 0:
Chris@87 126 seq_of_zeros = eigvals(seq_of_zeros)
Chris@87 127 elif len(sh) == 1:
Chris@87 128 pass
Chris@87 129 else:
Chris@87 130 raise ValueError("input must be 1d or non-empty square 2d array.")
Chris@87 131
Chris@87 132 if len(seq_of_zeros) == 0:
Chris@87 133 return 1.0
Chris@87 134
Chris@87 135 a = [1]
Chris@87 136 for k in range(len(seq_of_zeros)):
Chris@87 137 a = NX.convolve(a, [1, -seq_of_zeros[k]], mode='full')
Chris@87 138
Chris@87 139 if issubclass(a.dtype.type, NX.complexfloating):
Chris@87 140 # if complex roots are all complex conjugates, the roots are real.
Chris@87 141 roots = NX.asarray(seq_of_zeros, complex)
Chris@87 142 pos_roots = sort_complex(NX.compress(roots.imag > 0, roots))
Chris@87 143 neg_roots = NX.conjugate(sort_complex(
Chris@87 144 NX.compress(roots.imag < 0, roots)))
Chris@87 145 if (len(pos_roots) == len(neg_roots) and
Chris@87 146 NX.alltrue(neg_roots == pos_roots)):
Chris@87 147 a = a.real.copy()
Chris@87 148
Chris@87 149 return a
Chris@87 150
Chris@87 151 def roots(p):
Chris@87 152 """
Chris@87 153 Return the roots of a polynomial with coefficients given in p.
Chris@87 154
Chris@87 155 The values in the rank-1 array `p` are coefficients of a polynomial.
Chris@87 156 If the length of `p` is n+1 then the polynomial is described by::
Chris@87 157
Chris@87 158 p[0] * x**n + p[1] * x**(n-1) + ... + p[n-1]*x + p[n]
Chris@87 159
Chris@87 160 Parameters
Chris@87 161 ----------
Chris@87 162 p : array_like
Chris@87 163 Rank-1 array of polynomial coefficients.
Chris@87 164
Chris@87 165 Returns
Chris@87 166 -------
Chris@87 167 out : ndarray
Chris@87 168 An array containing the complex roots of the polynomial.
Chris@87 169
Chris@87 170 Raises
Chris@87 171 ------
Chris@87 172 ValueError
Chris@87 173 When `p` cannot be converted to a rank-1 array.
Chris@87 174
Chris@87 175 See also
Chris@87 176 --------
Chris@87 177 poly : Find the coefficients of a polynomial with a given sequence
Chris@87 178 of roots.
Chris@87 179 polyval : Evaluate a polynomial at a point.
Chris@87 180 polyfit : Least squares polynomial fit.
Chris@87 181 poly1d : A one-dimensional polynomial class.
Chris@87 182
Chris@87 183 Notes
Chris@87 184 -----
Chris@87 185 The algorithm relies on computing the eigenvalues of the
Chris@87 186 companion matrix [1]_.
Chris@87 187
Chris@87 188 References
Chris@87 189 ----------
Chris@87 190 .. [1] R. A. Horn & C. R. Johnson, *Matrix Analysis*. Cambridge, UK:
Chris@87 191 Cambridge University Press, 1999, pp. 146-7.
Chris@87 192
Chris@87 193 Examples
Chris@87 194 --------
Chris@87 195 >>> coeff = [3.2, 2, 1]
Chris@87 196 >>> np.roots(coeff)
Chris@87 197 array([-0.3125+0.46351241j, -0.3125-0.46351241j])
Chris@87 198
Chris@87 199 """
Chris@87 200 # If input is scalar, this makes it an array
Chris@87 201 p = atleast_1d(p)
Chris@87 202 if len(p.shape) != 1:
Chris@87 203 raise ValueError("Input must be a rank-1 array.")
Chris@87 204
Chris@87 205 # find non-zero array entries
Chris@87 206 non_zero = NX.nonzero(NX.ravel(p))[0]
Chris@87 207
Chris@87 208 # Return an empty array if polynomial is all zeros
Chris@87 209 if len(non_zero) == 0:
Chris@87 210 return NX.array([])
Chris@87 211
Chris@87 212 # find the number of trailing zeros -- this is the number of roots at 0.
Chris@87 213 trailing_zeros = len(p) - non_zero[-1] - 1
Chris@87 214
Chris@87 215 # strip leading and trailing zeros
Chris@87 216 p = p[int(non_zero[0]):int(non_zero[-1])+1]
Chris@87 217
Chris@87 218 # casting: if incoming array isn't floating point, make it floating point.
Chris@87 219 if not issubclass(p.dtype.type, (NX.floating, NX.complexfloating)):
Chris@87 220 p = p.astype(float)
Chris@87 221
Chris@87 222 N = len(p)
Chris@87 223 if N > 1:
Chris@87 224 # build companion matrix and find its eigenvalues (the roots)
Chris@87 225 A = diag(NX.ones((N-2,), p.dtype), -1)
Chris@87 226 A[0,:] = -p[1:] / p[0]
Chris@87 227 roots = eigvals(A)
Chris@87 228 else:
Chris@87 229 roots = NX.array([])
Chris@87 230
Chris@87 231 # tack any zeros onto the back of the array
Chris@87 232 roots = hstack((roots, NX.zeros(trailing_zeros, roots.dtype)))
Chris@87 233 return roots
Chris@87 234
Chris@87 235 def polyint(p, m=1, k=None):
Chris@87 236 """
Chris@87 237 Return an antiderivative (indefinite integral) of a polynomial.
Chris@87 238
Chris@87 239 The returned order `m` antiderivative `P` of polynomial `p` satisfies
Chris@87 240 :math:`\\frac{d^m}{dx^m}P(x) = p(x)` and is defined up to `m - 1`
Chris@87 241 integration constants `k`. The constants determine the low-order
Chris@87 242 polynomial part
Chris@87 243
Chris@87 244 .. math:: \\frac{k_{m-1}}{0!} x^0 + \\ldots + \\frac{k_0}{(m-1)!}x^{m-1}
Chris@87 245
Chris@87 246 of `P` so that :math:`P^{(j)}(0) = k_{m-j-1}`.
Chris@87 247
Chris@87 248 Parameters
Chris@87 249 ----------
Chris@87 250 p : {array_like, poly1d}
Chris@87 251 Polynomial to differentiate.
Chris@87 252 A sequence is interpreted as polynomial coefficients, see `poly1d`.
Chris@87 253 m : int, optional
Chris@87 254 Order of the antiderivative. (Default: 1)
Chris@87 255 k : {None, list of `m` scalars, scalar}, optional
Chris@87 256 Integration constants. They are given in the order of integration:
Chris@87 257 those corresponding to highest-order terms come first.
Chris@87 258
Chris@87 259 If ``None`` (default), all constants are assumed to be zero.
Chris@87 260 If `m = 1`, a single scalar can be given instead of a list.
Chris@87 261
Chris@87 262 See Also
Chris@87 263 --------
Chris@87 264 polyder : derivative of a polynomial
Chris@87 265 poly1d.integ : equivalent method
Chris@87 266
Chris@87 267 Examples
Chris@87 268 --------
Chris@87 269 The defining property of the antiderivative:
Chris@87 270
Chris@87 271 >>> p = np.poly1d([1,1,1])
Chris@87 272 >>> P = np.polyint(p)
Chris@87 273 >>> P
Chris@87 274 poly1d([ 0.33333333, 0.5 , 1. , 0. ])
Chris@87 275 >>> np.polyder(P) == p
Chris@87 276 True
Chris@87 277
Chris@87 278 The integration constants default to zero, but can be specified:
Chris@87 279
Chris@87 280 >>> P = np.polyint(p, 3)
Chris@87 281 >>> P(0)
Chris@87 282 0.0
Chris@87 283 >>> np.polyder(P)(0)
Chris@87 284 0.0
Chris@87 285 >>> np.polyder(P, 2)(0)
Chris@87 286 0.0
Chris@87 287 >>> P = np.polyint(p, 3, k=[6,5,3])
Chris@87 288 >>> P
Chris@87 289 poly1d([ 0.01666667, 0.04166667, 0.16666667, 3. , 5. , 3. ])
Chris@87 290
Chris@87 291 Note that 3 = 6 / 2!, and that the constants are given in the order of
Chris@87 292 integrations. Constant of the highest-order polynomial term comes first:
Chris@87 293
Chris@87 294 >>> np.polyder(P, 2)(0)
Chris@87 295 6.0
Chris@87 296 >>> np.polyder(P, 1)(0)
Chris@87 297 5.0
Chris@87 298 >>> P(0)
Chris@87 299 3.0
Chris@87 300
Chris@87 301 """
Chris@87 302 m = int(m)
Chris@87 303 if m < 0:
Chris@87 304 raise ValueError("Order of integral must be positive (see polyder)")
Chris@87 305 if k is None:
Chris@87 306 k = NX.zeros(m, float)
Chris@87 307 k = atleast_1d(k)
Chris@87 308 if len(k) == 1 and m > 1:
Chris@87 309 k = k[0]*NX.ones(m, float)
Chris@87 310 if len(k) < m:
Chris@87 311 raise ValueError(
Chris@87 312 "k must be a scalar or a rank-1 array of length 1 or >m.")
Chris@87 313
Chris@87 314 truepoly = isinstance(p, poly1d)
Chris@87 315 p = NX.asarray(p)
Chris@87 316 if m == 0:
Chris@87 317 if truepoly:
Chris@87 318 return poly1d(p)
Chris@87 319 return p
Chris@87 320 else:
Chris@87 321 # Note: this must work also with object and integer arrays
Chris@87 322 y = NX.concatenate((p.__truediv__(NX.arange(len(p), 0, -1)), [k[0]]))
Chris@87 323 val = polyint(y, m - 1, k=k[1:])
Chris@87 324 if truepoly:
Chris@87 325 return poly1d(val)
Chris@87 326 return val
Chris@87 327
Chris@87 328 def polyder(p, m=1):
Chris@87 329 """
Chris@87 330 Return the derivative of the specified order of a polynomial.
Chris@87 331
Chris@87 332 Parameters
Chris@87 333 ----------
Chris@87 334 p : poly1d or sequence
Chris@87 335 Polynomial to differentiate.
Chris@87 336 A sequence is interpreted as polynomial coefficients, see `poly1d`.
Chris@87 337 m : int, optional
Chris@87 338 Order of differentiation (default: 1)
Chris@87 339
Chris@87 340 Returns
Chris@87 341 -------
Chris@87 342 der : poly1d
Chris@87 343 A new polynomial representing the derivative.
Chris@87 344
Chris@87 345 See Also
Chris@87 346 --------
Chris@87 347 polyint : Anti-derivative of a polynomial.
Chris@87 348 poly1d : Class for one-dimensional polynomials.
Chris@87 349
Chris@87 350 Examples
Chris@87 351 --------
Chris@87 352 The derivative of the polynomial :math:`x^3 + x^2 + x^1 + 1` is:
Chris@87 353
Chris@87 354 >>> p = np.poly1d([1,1,1,1])
Chris@87 355 >>> p2 = np.polyder(p)
Chris@87 356 >>> p2
Chris@87 357 poly1d([3, 2, 1])
Chris@87 358
Chris@87 359 which evaluates to:
Chris@87 360
Chris@87 361 >>> p2(2.)
Chris@87 362 17.0
Chris@87 363
Chris@87 364 We can verify this, approximating the derivative with
Chris@87 365 ``(f(x + h) - f(x))/h``:
Chris@87 366
Chris@87 367 >>> (p(2. + 0.001) - p(2.)) / 0.001
Chris@87 368 17.007000999997857
Chris@87 369
Chris@87 370 The fourth-order derivative of a 3rd-order polynomial is zero:
Chris@87 371
Chris@87 372 >>> np.polyder(p, 2)
Chris@87 373 poly1d([6, 2])
Chris@87 374 >>> np.polyder(p, 3)
Chris@87 375 poly1d([6])
Chris@87 376 >>> np.polyder(p, 4)
Chris@87 377 poly1d([ 0.])
Chris@87 378
Chris@87 379 """
Chris@87 380 m = int(m)
Chris@87 381 if m < 0:
Chris@87 382 raise ValueError("Order of derivative must be positive (see polyint)")
Chris@87 383
Chris@87 384 truepoly = isinstance(p, poly1d)
Chris@87 385 p = NX.asarray(p)
Chris@87 386 n = len(p) - 1
Chris@87 387 y = p[:-1] * NX.arange(n, 0, -1)
Chris@87 388 if m == 0:
Chris@87 389 val = p
Chris@87 390 else:
Chris@87 391 val = polyder(y, m - 1)
Chris@87 392 if truepoly:
Chris@87 393 val = poly1d(val)
Chris@87 394 return val
Chris@87 395
Chris@87 396 def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
Chris@87 397 """
Chris@87 398 Least squares polynomial fit.
Chris@87 399
Chris@87 400 Fit a polynomial ``p(x) = p[0] * x**deg + ... + p[deg]`` of degree `deg`
Chris@87 401 to points `(x, y)`. Returns a vector of coefficients `p` that minimises
Chris@87 402 the squared error.
Chris@87 403
Chris@87 404 Parameters
Chris@87 405 ----------
Chris@87 406 x : array_like, shape (M,)
Chris@87 407 x-coordinates of the M sample points ``(x[i], y[i])``.
Chris@87 408 y : array_like, shape (M,) or (M, K)
Chris@87 409 y-coordinates of the sample points. Several data sets of sample
Chris@87 410 points sharing the same x-coordinates can be fitted at once by
Chris@87 411 passing in a 2D-array that contains one dataset per column.
Chris@87 412 deg : int
Chris@87 413 Degree of the fitting polynomial
Chris@87 414 rcond : float, optional
Chris@87 415 Relative condition number of the fit. Singular values smaller than
Chris@87 416 this relative to the largest singular value will be ignored. The
Chris@87 417 default value is len(x)*eps, where eps is the relative precision of
Chris@87 418 the float type, about 2e-16 in most cases.
Chris@87 419 full : bool, optional
Chris@87 420 Switch determining nature of return value. When it is False (the
Chris@87 421 default) just the coefficients are returned, when True diagnostic
Chris@87 422 information from the singular value decomposition is also returned.
Chris@87 423 w : array_like, shape (M,), optional
Chris@87 424 weights to apply to the y-coordinates of the sample points.
Chris@87 425 cov : bool, optional
Chris@87 426 Return the estimate and the covariance matrix of the estimate
Chris@87 427 If full is True, then cov is not returned.
Chris@87 428
Chris@87 429 Returns
Chris@87 430 -------
Chris@87 431 p : ndarray, shape (M,) or (M, K)
Chris@87 432 Polynomial coefficients, highest power first. If `y` was 2-D, the
Chris@87 433 coefficients for `k`-th data set are in ``p[:,k]``.
Chris@87 434
Chris@87 435 residuals, rank, singular_values, rcond :
Chris@87 436 Present only if `full` = True. Residuals of the least-squares fit,
Chris@87 437 the effective rank of the scaled Vandermonde coefficient matrix,
Chris@87 438 its singular values, and the specified value of `rcond`. For more
Chris@87 439 details, see `linalg.lstsq`.
Chris@87 440
Chris@87 441 V : ndarray, shape (M,M) or (M,M,K)
Chris@87 442 Present only if `full` = False and `cov`=True. The covariance
Chris@87 443 matrix of the polynomial coefficient estimates. The diagonal of
Chris@87 444 this matrix are the variance estimates for each coefficient. If y
Chris@87 445 is a 2-D array, then the covariance matrix for the `k`-th data set
Chris@87 446 are in ``V[:,:,k]``
Chris@87 447
Chris@87 448
Chris@87 449 Warns
Chris@87 450 -----
Chris@87 451 RankWarning
Chris@87 452 The rank of the coefficient matrix in the least-squares fit is
Chris@87 453 deficient. The warning is only raised if `full` = False.
Chris@87 454
Chris@87 455 The warnings can be turned off by
Chris@87 456
Chris@87 457 >>> import warnings
Chris@87 458 >>> warnings.simplefilter('ignore', np.RankWarning)
Chris@87 459
Chris@87 460 See Also
Chris@87 461 --------
Chris@87 462 polyval : Computes polynomial values.
Chris@87 463 linalg.lstsq : Computes a least-squares fit.
Chris@87 464 scipy.interpolate.UnivariateSpline : Computes spline fits.
Chris@87 465
Chris@87 466 Notes
Chris@87 467 -----
Chris@87 468 The solution minimizes the squared error
Chris@87 469
Chris@87 470 .. math ::
Chris@87 471 E = \\sum_{j=0}^k |p(x_j) - y_j|^2
Chris@87 472
Chris@87 473 in the equations::
Chris@87 474
Chris@87 475 x[0]**n * p[0] + ... + x[0] * p[n-1] + p[n] = y[0]
Chris@87 476 x[1]**n * p[0] + ... + x[1] * p[n-1] + p[n] = y[1]
Chris@87 477 ...
Chris@87 478 x[k]**n * p[0] + ... + x[k] * p[n-1] + p[n] = y[k]
Chris@87 479
Chris@87 480 The coefficient matrix of the coefficients `p` is a Vandermonde matrix.
Chris@87 481
Chris@87 482 `polyfit` issues a `RankWarning` when the least-squares fit is badly
Chris@87 483 conditioned. This implies that the best fit is not well-defined due
Chris@87 484 to numerical error. The results may be improved by lowering the polynomial
Chris@87 485 degree or by replacing `x` by `x` - `x`.mean(). The `rcond` parameter
Chris@87 486 can also be set to a value smaller than its default, but the resulting
Chris@87 487 fit may be spurious: including contributions from the small singular
Chris@87 488 values can add numerical noise to the result.
Chris@87 489
Chris@87 490 Note that fitting polynomial coefficients is inherently badly conditioned
Chris@87 491 when the degree of the polynomial is large or the interval of sample points
Chris@87 492 is badly centered. The quality of the fit should always be checked in these
Chris@87 493 cases. When polynomial fits are not satisfactory, splines may be a good
Chris@87 494 alternative.
Chris@87 495
Chris@87 496 References
Chris@87 497 ----------
Chris@87 498 .. [1] Wikipedia, "Curve fitting",
Chris@87 499 http://en.wikipedia.org/wiki/Curve_fitting
Chris@87 500 .. [2] Wikipedia, "Polynomial interpolation",
Chris@87 501 http://en.wikipedia.org/wiki/Polynomial_interpolation
Chris@87 502
Chris@87 503 Examples
Chris@87 504 --------
Chris@87 505 >>> x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
Chris@87 506 >>> y = np.array([0.0, 0.8, 0.9, 0.1, -0.8, -1.0])
Chris@87 507 >>> z = np.polyfit(x, y, 3)
Chris@87 508 >>> z
Chris@87 509 array([ 0.08703704, -0.81349206, 1.69312169, -0.03968254])
Chris@87 510
Chris@87 511 It is convenient to use `poly1d` objects for dealing with polynomials:
Chris@87 512
Chris@87 513 >>> p = np.poly1d(z)
Chris@87 514 >>> p(0.5)
Chris@87 515 0.6143849206349179
Chris@87 516 >>> p(3.5)
Chris@87 517 -0.34732142857143039
Chris@87 518 >>> p(10)
Chris@87 519 22.579365079365115
Chris@87 520
Chris@87 521 High-order polynomials may oscillate wildly:
Chris@87 522
Chris@87 523 >>> p30 = np.poly1d(np.polyfit(x, y, 30))
Chris@87 524 /... RankWarning: Polyfit may be poorly conditioned...
Chris@87 525 >>> p30(4)
Chris@87 526 -0.80000000000000204
Chris@87 527 >>> p30(5)
Chris@87 528 -0.99999999999999445
Chris@87 529 >>> p30(4.5)
Chris@87 530 -0.10547061179440398
Chris@87 531
Chris@87 532 Illustration:
Chris@87 533
Chris@87 534 >>> import matplotlib.pyplot as plt
Chris@87 535 >>> xp = np.linspace(-2, 6, 100)
Chris@87 536 >>> _ = plt.plot(x, y, '.', xp, p(xp), '-', xp, p30(xp), '--')
Chris@87 537 >>> plt.ylim(-2,2)
Chris@87 538 (-2, 2)
Chris@87 539 >>> plt.show()
Chris@87 540
Chris@87 541 """
Chris@87 542 order = int(deg) + 1
Chris@87 543 x = NX.asarray(x) + 0.0
Chris@87 544 y = NX.asarray(y) + 0.0
Chris@87 545
Chris@87 546 # check arguments.
Chris@87 547 if deg < 0:
Chris@87 548 raise ValueError("expected deg >= 0")
Chris@87 549 if x.ndim != 1:
Chris@87 550 raise TypeError("expected 1D vector for x")
Chris@87 551 if x.size == 0:
Chris@87 552 raise TypeError("expected non-empty vector for x")
Chris@87 553 if y.ndim < 1 or y.ndim > 2:
Chris@87 554 raise TypeError("expected 1D or 2D array for y")
Chris@87 555 if x.shape[0] != y.shape[0]:
Chris@87 556 raise TypeError("expected x and y to have same length")
Chris@87 557
Chris@87 558 # set rcond
Chris@87 559 if rcond is None:
Chris@87 560 rcond = len(x)*finfo(x.dtype).eps
Chris@87 561
Chris@87 562 # set up least squares equation for powers of x
Chris@87 563 lhs = vander(x, order)
Chris@87 564 rhs = y
Chris@87 565
Chris@87 566 # apply weighting
Chris@87 567 if w is not None:
Chris@87 568 w = NX.asarray(w) + 0.0
Chris@87 569 if w.ndim != 1:
Chris@87 570 raise TypeError("expected a 1-d array for weights")
Chris@87 571 if w.shape[0] != y.shape[0]:
Chris@87 572 raise TypeError("expected w and y to have the same length")
Chris@87 573 lhs *= w[:, NX.newaxis]
Chris@87 574 if rhs.ndim == 2:
Chris@87 575 rhs *= w[:, NX.newaxis]
Chris@87 576 else:
Chris@87 577 rhs *= w
Chris@87 578
Chris@87 579 # scale lhs to improve condition number and solve
Chris@87 580 scale = NX.sqrt((lhs*lhs).sum(axis=0))
Chris@87 581 lhs /= scale
Chris@87 582 c, resids, rank, s = lstsq(lhs, rhs, rcond)
Chris@87 583 c = (c.T/scale).T # broadcast scale coefficients
Chris@87 584
Chris@87 585 # warn on rank reduction, which indicates an ill conditioned matrix
Chris@87 586 if rank != order and not full:
Chris@87 587 msg = "Polyfit may be poorly conditioned"
Chris@87 588 warnings.warn(msg, RankWarning)
Chris@87 589
Chris@87 590 if full:
Chris@87 591 return c, resids, rank, s, rcond
Chris@87 592 elif cov:
Chris@87 593 Vbase = inv(dot(lhs.T, lhs))
Chris@87 594 Vbase /= NX.outer(scale, scale)
Chris@87 595 # Some literature ignores the extra -2.0 factor in the denominator, but
Chris@87 596 # it is included here because the covariance of Multivariate Student-T
Chris@87 597 # (which is implied by a Bayesian uncertainty analysis) includes it.
Chris@87 598 # Plus, it gives a slightly more conservative estimate of uncertainty.
Chris@87 599 fac = resids / (len(x) - order - 2.0)
Chris@87 600 if y.ndim == 1:
Chris@87 601 return c, Vbase * fac
Chris@87 602 else:
Chris@87 603 return c, Vbase[:,:, NX.newaxis] * fac
Chris@87 604 else:
Chris@87 605 return c
Chris@87 606
Chris@87 607
Chris@87 608 def polyval(p, x):
Chris@87 609 """
Chris@87 610 Evaluate a polynomial at specific values.
Chris@87 611
Chris@87 612 If `p` is of length N, this function returns the value:
Chris@87 613
Chris@87 614 ``p[0]*x**(N-1) + p[1]*x**(N-2) + ... + p[N-2]*x + p[N-1]``
Chris@87 615
Chris@87 616 If `x` is a sequence, then `p(x)` is returned for each element of `x`.
Chris@87 617 If `x` is another polynomial then the composite polynomial `p(x(t))`
Chris@87 618 is returned.
Chris@87 619
Chris@87 620 Parameters
Chris@87 621 ----------
Chris@87 622 p : array_like or poly1d object
Chris@87 623 1D array of polynomial coefficients (including coefficients equal
Chris@87 624 to zero) from highest degree to the constant term, or an
Chris@87 625 instance of poly1d.
Chris@87 626 x : array_like or poly1d object
Chris@87 627 A number, a 1D array of numbers, or an instance of poly1d, "at"
Chris@87 628 which to evaluate `p`.
Chris@87 629
Chris@87 630 Returns
Chris@87 631 -------
Chris@87 632 values : ndarray or poly1d
Chris@87 633 If `x` is a poly1d instance, the result is the composition of the two
Chris@87 634 polynomials, i.e., `x` is "substituted" in `p` and the simplified
Chris@87 635 result is returned. In addition, the type of `x` - array_like or
Chris@87 636 poly1d - governs the type of the output: `x` array_like => `values`
Chris@87 637 array_like, `x` a poly1d object => `values` is also.
Chris@87 638
Chris@87 639 See Also
Chris@87 640 --------
Chris@87 641 poly1d: A polynomial class.
Chris@87 642
Chris@87 643 Notes
Chris@87 644 -----
Chris@87 645 Horner's scheme [1]_ is used to evaluate the polynomial. Even so,
Chris@87 646 for polynomials of high degree the values may be inaccurate due to
Chris@87 647 rounding errors. Use carefully.
Chris@87 648
Chris@87 649 References
Chris@87 650 ----------
Chris@87 651 .. [1] I. N. Bronshtein, K. A. Semendyayev, and K. A. Hirsch (Eng.
Chris@87 652 trans. Ed.), *Handbook of Mathematics*, New York, Van Nostrand
Chris@87 653 Reinhold Co., 1985, pg. 720.
Chris@87 654
Chris@87 655 Examples
Chris@87 656 --------
Chris@87 657 >>> np.polyval([3,0,1], 5) # 3 * 5**2 + 0 * 5**1 + 1
Chris@87 658 76
Chris@87 659 >>> np.polyval([3,0,1], np.poly1d(5))
Chris@87 660 poly1d([ 76.])
Chris@87 661 >>> np.polyval(np.poly1d([3,0,1]), 5)
Chris@87 662 76
Chris@87 663 >>> np.polyval(np.poly1d([3,0,1]), np.poly1d(5))
Chris@87 664 poly1d([ 76.])
Chris@87 665
Chris@87 666 """
Chris@87 667 p = NX.asarray(p)
Chris@87 668 if isinstance(x, poly1d):
Chris@87 669 y = 0
Chris@87 670 else:
Chris@87 671 x = NX.asarray(x)
Chris@87 672 y = NX.zeros_like(x)
Chris@87 673 for i in range(len(p)):
Chris@87 674 y = x * y + p[i]
Chris@87 675 return y
Chris@87 676
Chris@87 677 def polyadd(a1, a2):
Chris@87 678 """
Chris@87 679 Find the sum of two polynomials.
Chris@87 680
Chris@87 681 Returns the polynomial resulting from the sum of two input polynomials.
Chris@87 682 Each input must be either a poly1d object or a 1D sequence of polynomial
Chris@87 683 coefficients, from highest to lowest degree.
Chris@87 684
Chris@87 685 Parameters
Chris@87 686 ----------
Chris@87 687 a1, a2 : array_like or poly1d object
Chris@87 688 Input polynomials.
Chris@87 689
Chris@87 690 Returns
Chris@87 691 -------
Chris@87 692 out : ndarray or poly1d object
Chris@87 693 The sum of the inputs. If either input is a poly1d object, then the
Chris@87 694 output is also a poly1d object. Otherwise, it is a 1D array of
Chris@87 695 polynomial coefficients from highest to lowest degree.
Chris@87 696
Chris@87 697 See Also
Chris@87 698 --------
Chris@87 699 poly1d : A one-dimensional polynomial class.
Chris@87 700 poly, polyadd, polyder, polydiv, polyfit, polyint, polysub, polyval
Chris@87 701
Chris@87 702 Examples
Chris@87 703 --------
Chris@87 704 >>> np.polyadd([1, 2], [9, 5, 4])
Chris@87 705 array([9, 6, 6])
Chris@87 706
Chris@87 707 Using poly1d objects:
Chris@87 708
Chris@87 709 >>> p1 = np.poly1d([1, 2])
Chris@87 710 >>> p2 = np.poly1d([9, 5, 4])
Chris@87 711 >>> print p1
Chris@87 712 1 x + 2
Chris@87 713 >>> print p2
Chris@87 714 2
Chris@87 715 9 x + 5 x + 4
Chris@87 716 >>> print np.polyadd(p1, p2)
Chris@87 717 2
Chris@87 718 9 x + 6 x + 6
Chris@87 719
Chris@87 720 """
Chris@87 721 truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
Chris@87 722 a1 = atleast_1d(a1)
Chris@87 723 a2 = atleast_1d(a2)
Chris@87 724 diff = len(a2) - len(a1)
Chris@87 725 if diff == 0:
Chris@87 726 val = a1 + a2
Chris@87 727 elif diff > 0:
Chris@87 728 zr = NX.zeros(diff, a1.dtype)
Chris@87 729 val = NX.concatenate((zr, a1)) + a2
Chris@87 730 else:
Chris@87 731 zr = NX.zeros(abs(diff), a2.dtype)
Chris@87 732 val = a1 + NX.concatenate((zr, a2))
Chris@87 733 if truepoly:
Chris@87 734 val = poly1d(val)
Chris@87 735 return val
Chris@87 736
Chris@87 737 def polysub(a1, a2):
Chris@87 738 """
Chris@87 739 Difference (subtraction) of two polynomials.
Chris@87 740
Chris@87 741 Given two polynomials `a1` and `a2`, returns ``a1 - a2``.
Chris@87 742 `a1` and `a2` can be either array_like sequences of the polynomials'
Chris@87 743 coefficients (including coefficients equal to zero), or `poly1d` objects.
Chris@87 744
Chris@87 745 Parameters
Chris@87 746 ----------
Chris@87 747 a1, a2 : array_like or poly1d
Chris@87 748 Minuend and subtrahend polynomials, respectively.
Chris@87 749
Chris@87 750 Returns
Chris@87 751 -------
Chris@87 752 out : ndarray or poly1d
Chris@87 753 Array or `poly1d` object of the difference polynomial's coefficients.
Chris@87 754
Chris@87 755 See Also
Chris@87 756 --------
Chris@87 757 polyval, polydiv, polymul, polyadd
Chris@87 758
Chris@87 759 Examples
Chris@87 760 --------
Chris@87 761 .. math:: (2 x^2 + 10 x - 2) - (3 x^2 + 10 x -4) = (-x^2 + 2)
Chris@87 762
Chris@87 763 >>> np.polysub([2, 10, -2], [3, 10, -4])
Chris@87 764 array([-1, 0, 2])
Chris@87 765
Chris@87 766 """
Chris@87 767 truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
Chris@87 768 a1 = atleast_1d(a1)
Chris@87 769 a2 = atleast_1d(a2)
Chris@87 770 diff = len(a2) - len(a1)
Chris@87 771 if diff == 0:
Chris@87 772 val = a1 - a2
Chris@87 773 elif diff > 0:
Chris@87 774 zr = NX.zeros(diff, a1.dtype)
Chris@87 775 val = NX.concatenate((zr, a1)) - a2
Chris@87 776 else:
Chris@87 777 zr = NX.zeros(abs(diff), a2.dtype)
Chris@87 778 val = a1 - NX.concatenate((zr, a2))
Chris@87 779 if truepoly:
Chris@87 780 val = poly1d(val)
Chris@87 781 return val
Chris@87 782
Chris@87 783
Chris@87 784 def polymul(a1, a2):
Chris@87 785 """
Chris@87 786 Find the product of two polynomials.
Chris@87 787
Chris@87 788 Finds the polynomial resulting from the multiplication of the two input
Chris@87 789 polynomials. Each input must be either a poly1d object or a 1D sequence
Chris@87 790 of polynomial coefficients, from highest to lowest degree.
Chris@87 791
Chris@87 792 Parameters
Chris@87 793 ----------
Chris@87 794 a1, a2 : array_like or poly1d object
Chris@87 795 Input polynomials.
Chris@87 796
Chris@87 797 Returns
Chris@87 798 -------
Chris@87 799 out : ndarray or poly1d object
Chris@87 800 The polynomial resulting from the multiplication of the inputs. If
Chris@87 801 either inputs is a poly1d object, then the output is also a poly1d
Chris@87 802 object. Otherwise, it is a 1D array of polynomial coefficients from
Chris@87 803 highest to lowest degree.
Chris@87 804
Chris@87 805 See Also
Chris@87 806 --------
Chris@87 807 poly1d : A one-dimensional polynomial class.
Chris@87 808 poly, polyadd, polyder, polydiv, polyfit, polyint, polysub,
Chris@87 809 polyval
Chris@87 810 convolve : Array convolution. Same output as polymul, but has parameter
Chris@87 811 for overlap mode.
Chris@87 812
Chris@87 813 Examples
Chris@87 814 --------
Chris@87 815 >>> np.polymul([1, 2, 3], [9, 5, 1])
Chris@87 816 array([ 9, 23, 38, 17, 3])
Chris@87 817
Chris@87 818 Using poly1d objects:
Chris@87 819
Chris@87 820 >>> p1 = np.poly1d([1, 2, 3])
Chris@87 821 >>> p2 = np.poly1d([9, 5, 1])
Chris@87 822 >>> print p1
Chris@87 823 2
Chris@87 824 1 x + 2 x + 3
Chris@87 825 >>> print p2
Chris@87 826 2
Chris@87 827 9 x + 5 x + 1
Chris@87 828 >>> print np.polymul(p1, p2)
Chris@87 829 4 3 2
Chris@87 830 9 x + 23 x + 38 x + 17 x + 3
Chris@87 831
Chris@87 832 """
Chris@87 833 truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
Chris@87 834 a1, a2 = poly1d(a1), poly1d(a2)
Chris@87 835 val = NX.convolve(a1, a2)
Chris@87 836 if truepoly:
Chris@87 837 val = poly1d(val)
Chris@87 838 return val
Chris@87 839
Chris@87 840 def polydiv(u, v):
Chris@87 841 """
Chris@87 842 Returns the quotient and remainder of polynomial division.
Chris@87 843
Chris@87 844 The input arrays are the coefficients (including any coefficients
Chris@87 845 equal to zero) of the "numerator" (dividend) and "denominator"
Chris@87 846 (divisor) polynomials, respectively.
Chris@87 847
Chris@87 848 Parameters
Chris@87 849 ----------
Chris@87 850 u : array_like or poly1d
Chris@87 851 Dividend polynomial's coefficients.
Chris@87 852
Chris@87 853 v : array_like or poly1d
Chris@87 854 Divisor polynomial's coefficients.
Chris@87 855
Chris@87 856 Returns
Chris@87 857 -------
Chris@87 858 q : ndarray
Chris@87 859 Coefficients, including those equal to zero, of the quotient.
Chris@87 860 r : ndarray
Chris@87 861 Coefficients, including those equal to zero, of the remainder.
Chris@87 862
Chris@87 863 See Also
Chris@87 864 --------
Chris@87 865 poly, polyadd, polyder, polydiv, polyfit, polyint, polymul, polysub,
Chris@87 866 polyval
Chris@87 867
Chris@87 868 Notes
Chris@87 869 -----
Chris@87 870 Both `u` and `v` must be 0-d or 1-d (ndim = 0 or 1), but `u.ndim` need
Chris@87 871 not equal `v.ndim`. In other words, all four possible combinations -
Chris@87 872 ``u.ndim = v.ndim = 0``, ``u.ndim = v.ndim = 1``,
Chris@87 873 ``u.ndim = 1, v.ndim = 0``, and ``u.ndim = 0, v.ndim = 1`` - work.
Chris@87 874
Chris@87 875 Examples
Chris@87 876 --------
Chris@87 877 .. math:: \\frac{3x^2 + 5x + 2}{2x + 1} = 1.5x + 1.75, remainder 0.25
Chris@87 878
Chris@87 879 >>> x = np.array([3.0, 5.0, 2.0])
Chris@87 880 >>> y = np.array([2.0, 1.0])
Chris@87 881 >>> np.polydiv(x, y)
Chris@87 882 (array([ 1.5 , 1.75]), array([ 0.25]))
Chris@87 883
Chris@87 884 """
Chris@87 885 truepoly = (isinstance(u, poly1d) or isinstance(u, poly1d))
Chris@87 886 u = atleast_1d(u) + 0.0
Chris@87 887 v = atleast_1d(v) + 0.0
Chris@87 888 # w has the common type
Chris@87 889 w = u[0] + v[0]
Chris@87 890 m = len(u) - 1
Chris@87 891 n = len(v) - 1
Chris@87 892 scale = 1. / v[0]
Chris@87 893 q = NX.zeros((max(m - n + 1, 1),), w.dtype)
Chris@87 894 r = u.copy()
Chris@87 895 for k in range(0, m-n+1):
Chris@87 896 d = scale * r[k]
Chris@87 897 q[k] = d
Chris@87 898 r[k:k+n+1] -= d*v
Chris@87 899 while NX.allclose(r[0], 0, rtol=1e-14) and (r.shape[-1] > 1):
Chris@87 900 r = r[1:]
Chris@87 901 if truepoly:
Chris@87 902 return poly1d(q), poly1d(r)
Chris@87 903 return q, r
Chris@87 904
Chris@87 905 _poly_mat = re.compile(r"[*][*]([0-9]*)")
Chris@87 906 def _raise_power(astr, wrap=70):
Chris@87 907 n = 0
Chris@87 908 line1 = ''
Chris@87 909 line2 = ''
Chris@87 910 output = ' '
Chris@87 911 while True:
Chris@87 912 mat = _poly_mat.search(astr, n)
Chris@87 913 if mat is None:
Chris@87 914 break
Chris@87 915 span = mat.span()
Chris@87 916 power = mat.groups()[0]
Chris@87 917 partstr = astr[n:span[0]]
Chris@87 918 n = span[1]
Chris@87 919 toadd2 = partstr + ' '*(len(power)-1)
Chris@87 920 toadd1 = ' '*(len(partstr)-1) + power
Chris@87 921 if ((len(line2) + len(toadd2) > wrap) or
Chris@87 922 (len(line1) + len(toadd1) > wrap)):
Chris@87 923 output += line1 + "\n" + line2 + "\n "
Chris@87 924 line1 = toadd1
Chris@87 925 line2 = toadd2
Chris@87 926 else:
Chris@87 927 line2 += partstr + ' '*(len(power)-1)
Chris@87 928 line1 += ' '*(len(partstr)-1) + power
Chris@87 929 output += line1 + "\n" + line2
Chris@87 930 return output + astr[n:]
Chris@87 931
Chris@87 932
Chris@87 933 class poly1d(object):
Chris@87 934 """
Chris@87 935 A one-dimensional polynomial class.
Chris@87 936
Chris@87 937 A convenience class, used to encapsulate "natural" operations on
Chris@87 938 polynomials so that said operations may take on their customary
Chris@87 939 form in code (see Examples).
Chris@87 940
Chris@87 941 Parameters
Chris@87 942 ----------
Chris@87 943 c_or_r : array_like
Chris@87 944 The polynomial's coefficients, in decreasing powers, or if
Chris@87 945 the value of the second parameter is True, the polynomial's
Chris@87 946 roots (values where the polynomial evaluates to 0). For example,
Chris@87 947 ``poly1d([1, 2, 3])`` returns an object that represents
Chris@87 948 :math:`x^2 + 2x + 3`, whereas ``poly1d([1, 2, 3], True)`` returns
Chris@87 949 one that represents :math:`(x-1)(x-2)(x-3) = x^3 - 6x^2 + 11x -6`.
Chris@87 950 r : bool, optional
Chris@87 951 If True, `c_or_r` specifies the polynomial's roots; the default
Chris@87 952 is False.
Chris@87 953 variable : str, optional
Chris@87 954 Changes the variable used when printing `p` from `x` to `variable`
Chris@87 955 (see Examples).
Chris@87 956
Chris@87 957 Examples
Chris@87 958 --------
Chris@87 959 Construct the polynomial :math:`x^2 + 2x + 3`:
Chris@87 960
Chris@87 961 >>> p = np.poly1d([1, 2, 3])
Chris@87 962 >>> print np.poly1d(p)
Chris@87 963 2
Chris@87 964 1 x + 2 x + 3
Chris@87 965
Chris@87 966 Evaluate the polynomial at :math:`x = 0.5`:
Chris@87 967
Chris@87 968 >>> p(0.5)
Chris@87 969 4.25
Chris@87 970
Chris@87 971 Find the roots:
Chris@87 972
Chris@87 973 >>> p.r
Chris@87 974 array([-1.+1.41421356j, -1.-1.41421356j])
Chris@87 975 >>> p(p.r)
Chris@87 976 array([ -4.44089210e-16+0.j, -4.44089210e-16+0.j])
Chris@87 977
Chris@87 978 These numbers in the previous line represent (0, 0) to machine precision
Chris@87 979
Chris@87 980 Show the coefficients:
Chris@87 981
Chris@87 982 >>> p.c
Chris@87 983 array([1, 2, 3])
Chris@87 984
Chris@87 985 Display the order (the leading zero-coefficients are removed):
Chris@87 986
Chris@87 987 >>> p.order
Chris@87 988 2
Chris@87 989
Chris@87 990 Show the coefficient of the k-th power in the polynomial
Chris@87 991 (which is equivalent to ``p.c[-(i+1)]``):
Chris@87 992
Chris@87 993 >>> p[1]
Chris@87 994 2
Chris@87 995
Chris@87 996 Polynomials can be added, subtracted, multiplied, and divided
Chris@87 997 (returns quotient and remainder):
Chris@87 998
Chris@87 999 >>> p * p
Chris@87 1000 poly1d([ 1, 4, 10, 12, 9])
Chris@87 1001
Chris@87 1002 >>> (p**3 + 4) / p
Chris@87 1003 (poly1d([ 1., 4., 10., 12., 9.]), poly1d([ 4.]))
Chris@87 1004
Chris@87 1005 ``asarray(p)`` gives the coefficient array, so polynomials can be
Chris@87 1006 used in all functions that accept arrays:
Chris@87 1007
Chris@87 1008 >>> p**2 # square of polynomial
Chris@87 1009 poly1d([ 1, 4, 10, 12, 9])
Chris@87 1010
Chris@87 1011 >>> np.square(p) # square of individual coefficients
Chris@87 1012 array([1, 4, 9])
Chris@87 1013
Chris@87 1014 The variable used in the string representation of `p` can be modified,
Chris@87 1015 using the `variable` parameter:
Chris@87 1016
Chris@87 1017 >>> p = np.poly1d([1,2,3], variable='z')
Chris@87 1018 >>> print p
Chris@87 1019 2
Chris@87 1020 1 z + 2 z + 3
Chris@87 1021
Chris@87 1022 Construct a polynomial from its roots:
Chris@87 1023
Chris@87 1024 >>> np.poly1d([1, 2], True)
Chris@87 1025 poly1d([ 1, -3, 2])
Chris@87 1026
Chris@87 1027 This is the same polynomial as obtained by:
Chris@87 1028
Chris@87 1029 >>> np.poly1d([1, -1]) * np.poly1d([1, -2])
Chris@87 1030 poly1d([ 1, -3, 2])
Chris@87 1031
Chris@87 1032 """
Chris@87 1033 coeffs = None
Chris@87 1034 order = None
Chris@87 1035 variable = None
Chris@87 1036 __hash__ = None
Chris@87 1037
Chris@87 1038 def __init__(self, c_or_r, r=0, variable=None):
Chris@87 1039 if isinstance(c_or_r, poly1d):
Chris@87 1040 for key in c_or_r.__dict__.keys():
Chris@87 1041 self.__dict__[key] = c_or_r.__dict__[key]
Chris@87 1042 if variable is not None:
Chris@87 1043 self.__dict__['variable'] = variable
Chris@87 1044 return
Chris@87 1045 if r:
Chris@87 1046 c_or_r = poly(c_or_r)
Chris@87 1047 c_or_r = atleast_1d(c_or_r)
Chris@87 1048 if len(c_or_r.shape) > 1:
Chris@87 1049 raise ValueError("Polynomial must be 1d only.")
Chris@87 1050 c_or_r = trim_zeros(c_or_r, trim='f')
Chris@87 1051 if len(c_or_r) == 0:
Chris@87 1052 c_or_r = NX.array([0.])
Chris@87 1053 self.__dict__['coeffs'] = c_or_r
Chris@87 1054 self.__dict__['order'] = len(c_or_r) - 1
Chris@87 1055 if variable is None:
Chris@87 1056 variable = 'x'
Chris@87 1057 self.__dict__['variable'] = variable
Chris@87 1058
Chris@87 1059 def __array__(self, t=None):
Chris@87 1060 if t:
Chris@87 1061 return NX.asarray(self.coeffs, t)
Chris@87 1062 else:
Chris@87 1063 return NX.asarray(self.coeffs)
Chris@87 1064
Chris@87 1065 def __repr__(self):
Chris@87 1066 vals = repr(self.coeffs)
Chris@87 1067 vals = vals[6:-1]
Chris@87 1068 return "poly1d(%s)" % vals
Chris@87 1069
Chris@87 1070 def __len__(self):
Chris@87 1071 return self.order
Chris@87 1072
Chris@87 1073 def __str__(self):
Chris@87 1074 thestr = "0"
Chris@87 1075 var = self.variable
Chris@87 1076
Chris@87 1077 # Remove leading zeros
Chris@87 1078 coeffs = self.coeffs[NX.logical_or.accumulate(self.coeffs != 0)]
Chris@87 1079 N = len(coeffs)-1
Chris@87 1080
Chris@87 1081 def fmt_float(q):
Chris@87 1082 s = '%.4g' % q
Chris@87 1083 if s.endswith('.0000'):
Chris@87 1084 s = s[:-5]
Chris@87 1085 return s
Chris@87 1086
Chris@87 1087 for k in range(len(coeffs)):
Chris@87 1088 if not iscomplex(coeffs[k]):
Chris@87 1089 coefstr = fmt_float(real(coeffs[k]))
Chris@87 1090 elif real(coeffs[k]) == 0:
Chris@87 1091 coefstr = '%sj' % fmt_float(imag(coeffs[k]))
Chris@87 1092 else:
Chris@87 1093 coefstr = '(%s + %sj)' % (fmt_float(real(coeffs[k])),
Chris@87 1094 fmt_float(imag(coeffs[k])))
Chris@87 1095
Chris@87 1096 power = (N-k)
Chris@87 1097 if power == 0:
Chris@87 1098 if coefstr != '0':
Chris@87 1099 newstr = '%s' % (coefstr,)
Chris@87 1100 else:
Chris@87 1101 if k == 0:
Chris@87 1102 newstr = '0'
Chris@87 1103 else:
Chris@87 1104 newstr = ''
Chris@87 1105 elif power == 1:
Chris@87 1106 if coefstr == '0':
Chris@87 1107 newstr = ''
Chris@87 1108 elif coefstr == 'b':
Chris@87 1109 newstr = var
Chris@87 1110 else:
Chris@87 1111 newstr = '%s %s' % (coefstr, var)
Chris@87 1112 else:
Chris@87 1113 if coefstr == '0':
Chris@87 1114 newstr = ''
Chris@87 1115 elif coefstr == 'b':
Chris@87 1116 newstr = '%s**%d' % (var, power,)
Chris@87 1117 else:
Chris@87 1118 newstr = '%s %s**%d' % (coefstr, var, power)
Chris@87 1119
Chris@87 1120 if k > 0:
Chris@87 1121 if newstr != '':
Chris@87 1122 if newstr.startswith('-'):
Chris@87 1123 thestr = "%s - %s" % (thestr, newstr[1:])
Chris@87 1124 else:
Chris@87 1125 thestr = "%s + %s" % (thestr, newstr)
Chris@87 1126 else:
Chris@87 1127 thestr = newstr
Chris@87 1128 return _raise_power(thestr)
Chris@87 1129
Chris@87 1130 def __call__(self, val):
Chris@87 1131 return polyval(self.coeffs, val)
Chris@87 1132
Chris@87 1133 def __neg__(self):
Chris@87 1134 return poly1d(-self.coeffs)
Chris@87 1135
Chris@87 1136 def __pos__(self):
Chris@87 1137 return self
Chris@87 1138
Chris@87 1139 def __mul__(self, other):
Chris@87 1140 if isscalar(other):
Chris@87 1141 return poly1d(self.coeffs * other)
Chris@87 1142 else:
Chris@87 1143 other = poly1d(other)
Chris@87 1144 return poly1d(polymul(self.coeffs, other.coeffs))
Chris@87 1145
Chris@87 1146 def __rmul__(self, other):
Chris@87 1147 if isscalar(other):
Chris@87 1148 return poly1d(other * self.coeffs)
Chris@87 1149 else:
Chris@87 1150 other = poly1d(other)
Chris@87 1151 return poly1d(polymul(self.coeffs, other.coeffs))
Chris@87 1152
Chris@87 1153 def __add__(self, other):
Chris@87 1154 other = poly1d(other)
Chris@87 1155 return poly1d(polyadd(self.coeffs, other.coeffs))
Chris@87 1156
Chris@87 1157 def __radd__(self, other):
Chris@87 1158 other = poly1d(other)
Chris@87 1159 return poly1d(polyadd(self.coeffs, other.coeffs))
Chris@87 1160
Chris@87 1161 def __pow__(self, val):
Chris@87 1162 if not isscalar(val) or int(val) != val or val < 0:
Chris@87 1163 raise ValueError("Power to non-negative integers only.")
Chris@87 1164 res = [1]
Chris@87 1165 for _ in range(val):
Chris@87 1166 res = polymul(self.coeffs, res)
Chris@87 1167 return poly1d(res)
Chris@87 1168
Chris@87 1169 def __sub__(self, other):
Chris@87 1170 other = poly1d(other)
Chris@87 1171 return poly1d(polysub(self.coeffs, other.coeffs))
Chris@87 1172
Chris@87 1173 def __rsub__(self, other):
Chris@87 1174 other = poly1d(other)
Chris@87 1175 return poly1d(polysub(other.coeffs, self.coeffs))
Chris@87 1176
Chris@87 1177 def __div__(self, other):
Chris@87 1178 if isscalar(other):
Chris@87 1179 return poly1d(self.coeffs/other)
Chris@87 1180 else:
Chris@87 1181 other = poly1d(other)
Chris@87 1182 return polydiv(self, other)
Chris@87 1183
Chris@87 1184 __truediv__ = __div__
Chris@87 1185
Chris@87 1186 def __rdiv__(self, other):
Chris@87 1187 if isscalar(other):
Chris@87 1188 return poly1d(other/self.coeffs)
Chris@87 1189 else:
Chris@87 1190 other = poly1d(other)
Chris@87 1191 return polydiv(other, self)
Chris@87 1192
Chris@87 1193 __rtruediv__ = __rdiv__
Chris@87 1194
Chris@87 1195 def __eq__(self, other):
Chris@87 1196 if self.coeffs.shape != other.coeffs.shape:
Chris@87 1197 return False
Chris@87 1198 return (self.coeffs == other.coeffs).all()
Chris@87 1199
Chris@87 1200 def __ne__(self, other):
Chris@87 1201 return not self.__eq__(other)
Chris@87 1202
Chris@87 1203 def __setattr__(self, key, val):
Chris@87 1204 raise ValueError("Attributes cannot be changed this way.")
Chris@87 1205
Chris@87 1206 def __getattr__(self, key):
Chris@87 1207 if key in ['r', 'roots']:
Chris@87 1208 return roots(self.coeffs)
Chris@87 1209 elif key in ['c', 'coef', 'coefficients']:
Chris@87 1210 return self.coeffs
Chris@87 1211 elif key in ['o']:
Chris@87 1212 return self.order
Chris@87 1213 else:
Chris@87 1214 try:
Chris@87 1215 return self.__dict__[key]
Chris@87 1216 except KeyError:
Chris@87 1217 raise AttributeError(
Chris@87 1218 "'%s' has no attribute '%s'" % (self.__class__, key))
Chris@87 1219
Chris@87 1220 def __getitem__(self, val):
Chris@87 1221 ind = self.order - val
Chris@87 1222 if val > self.order:
Chris@87 1223 return 0
Chris@87 1224 if val < 0:
Chris@87 1225 return 0
Chris@87 1226 return self.coeffs[ind]
Chris@87 1227
Chris@87 1228 def __setitem__(self, key, val):
Chris@87 1229 ind = self.order - key
Chris@87 1230 if key < 0:
Chris@87 1231 raise ValueError("Does not support negative powers.")
Chris@87 1232 if key > self.order:
Chris@87 1233 zr = NX.zeros(key-self.order, self.coeffs.dtype)
Chris@87 1234 self.__dict__['coeffs'] = NX.concatenate((zr, self.coeffs))
Chris@87 1235 self.__dict__['order'] = key
Chris@87 1236 ind = 0
Chris@87 1237 self.__dict__['coeffs'][ind] = val
Chris@87 1238 return
Chris@87 1239
Chris@87 1240 def __iter__(self):
Chris@87 1241 return iter(self.coeffs)
Chris@87 1242
Chris@87 1243 def integ(self, m=1, k=0):
Chris@87 1244 """
Chris@87 1245 Return an antiderivative (indefinite integral) of this polynomial.
Chris@87 1246
Chris@87 1247 Refer to `polyint` for full documentation.
Chris@87 1248
Chris@87 1249 See Also
Chris@87 1250 --------
Chris@87 1251 polyint : equivalent function
Chris@87 1252
Chris@87 1253 """
Chris@87 1254 return poly1d(polyint(self.coeffs, m=m, k=k))
Chris@87 1255
Chris@87 1256 def deriv(self, m=1):
Chris@87 1257 """
Chris@87 1258 Return a derivative of this polynomial.
Chris@87 1259
Chris@87 1260 Refer to `polyder` for full documentation.
Chris@87 1261
Chris@87 1262 See Also
Chris@87 1263 --------
Chris@87 1264 polyder : equivalent function
Chris@87 1265
Chris@87 1266 """
Chris@87 1267 return poly1d(polyder(self.coeffs, m=m))
Chris@87 1268
Chris@87 1269 # Stuff to do on module import
Chris@87 1270
Chris@87 1271 warnings.simplefilter('always', RankWarning)