Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/numpy/lib/_polynomial_impl.py: 21%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

433 statements  

1""" 

2Functions to operate on polynomials. 

3 

4""" 

5__all__ = ['poly', 'roots', 'polyint', 'polyder', 'polyadd', 

6 'polysub', 'polymul', 'polydiv', 'polyval', 'poly1d', 

7 'polyfit'] 

8 

9import functools 

10import re 

11import warnings 

12 

13import numpy._core.numeric as NX 

14from numpy._core import ( 

15 abs, 

16 array, 

17 atleast_1d, 

18 dot, 

19 finfo, 

20 hstack, 

21 isscalar, 

22 ones, 

23 overrides, 

24) 

25from numpy._utils import set_module 

26from numpy.exceptions import RankWarning 

27from numpy.lib._function_base_impl import trim_zeros 

28from numpy.lib._twodim_base_impl import diag, vander 

29from numpy.lib._type_check_impl import imag, iscomplex, mintypecode, real 

30from numpy.linalg import eigvals, inv, lstsq 

31 

32array_function_dispatch = functools.partial( 

33 overrides.array_function_dispatch, module='numpy') 

34 

35 

36def _poly_dispatcher(seq_of_zeros): 

37 return seq_of_zeros 

38 

39 

40@array_function_dispatch(_poly_dispatcher) 

41def poly(seq_of_zeros): 

42 """ 

43 Find the coefficients of a polynomial with the given sequence of roots. 

44 

45 .. note:: 

46 This forms part of the old polynomial API. Since version 1.4, the 

47 new polynomial API defined in `numpy.polynomial` is preferred. 

48 A summary of the differences can be found in the 

49 :doc:`transition guide </reference/routines.polynomials>`. 

50 

51 Returns the coefficients of the polynomial whose leading coefficient 

52 is one for the given sequence of zeros (multiple roots must be included 

53 in the sequence as many times as their multiplicity; see Examples). 

54 A square matrix (or array, which will be treated as a matrix) can also 

55 be given, in which case the coefficients of the characteristic polynomial 

56 of the matrix are returned. 

57 

58 Parameters 

59 ---------- 

60 seq_of_zeros : array_like, shape (N,) or (N, N) 

61 A sequence of polynomial roots, or a square array or matrix object. 

62 

63 Returns 

64 ------- 

65 c : ndarray 

66 1D array of polynomial coefficients from highest to lowest degree: 

67 

68 ``c[0] * x**(N) + c[1] * x**(N-1) + ... + c[N-1] * x + c[N]`` 

69 where c[0] always equals 1. 

70 

71 Raises 

72 ------ 

73 ValueError 

74 If input is the wrong shape (the input must be a 1-D or square 

75 2-D array). 

76 

77 See Also 

78 -------- 

79 polyval : Compute polynomial values. 

80 roots : Return the roots of a polynomial. 

81 polyfit : Least squares polynomial fit. 

82 poly1d : A one-dimensional polynomial class. 

83 

84 Notes 

85 ----- 

86 Specifying the roots of a polynomial still leaves one degree of 

87 freedom, typically represented by an undetermined leading 

88 coefficient. [1]_ In the case of this function, that coefficient - 

89 the first one in the returned array - is always taken as one. (If 

90 for some reason you have one other point, the only automatic way 

91 presently to leverage that information is to use ``polyfit``.) 

92 

93 The characteristic polynomial, :math:`p_a(t)`, of an `n`-by-`n` 

94 matrix **A** is given by 

95 

96 :math:`p_a(t) = \\mathrm{det}(t\\, \\mathbf{I} - \\mathbf{A})`, 

97 

98 where **I** is the `n`-by-`n` identity matrix. [2]_ 

99 

100 References 

101 ---------- 

102 .. [1] M. Sullivan and M. Sullivan, III, "Algebra and Trigonometry, 

103 Enhanced With Graphing Utilities," Prentice-Hall, pg. 318, 1996. 

104 

105 .. [2] G. Strang, "Linear Algebra and Its Applications, 2nd Edition," 

106 Academic Press, pg. 182, 1980. 

107 

108 Examples 

109 -------- 

110 

111 Given a sequence of a polynomial's zeros: 

112 

113 >>> import numpy as np 

114 

115 >>> np.poly((0, 0, 0)) # Multiple root example 

116 array([1., 0., 0., 0.]) 

117 

118 The line above represents z**3 + 0*z**2 + 0*z + 0. 

119 

120 >>> np.poly((-1./2, 0, 1./2)) 

121 array([ 1. , 0. , -0.25, 0. ]) 

122 

123 The line above represents z**3 - z/4 

124 

125 >>> np.poly((np.random.random(1)[0], 0, np.random.random(1)[0])) 

126 array([ 1. , -0.77086955, 0.08618131, 0. ]) # random 

127 

128 Given a square array object: 

129 

130 >>> P = np.array([[0, 1./3], [-1./2, 0]]) 

131 >>> np.poly(P) 

132 array([1. , 0. , 0.16666667]) 

133 

134 Note how in all cases the leading coefficient is always 1. 

135 

136 """ 

137 seq_of_zeros = atleast_1d(seq_of_zeros) 

138 sh = seq_of_zeros.shape 

139 

140 if len(sh) == 2 and sh[0] == sh[1] and sh[0] != 0: 

141 seq_of_zeros = eigvals(seq_of_zeros) 

142 elif len(sh) == 1: 

143 dt = seq_of_zeros.dtype 

144 # Let object arrays slip through, e.g. for arbitrary precision 

145 if dt != object: 

146 seq_of_zeros = seq_of_zeros.astype(mintypecode(dt.char)) 

147 else: 

148 raise ValueError("input must be 1d or non-empty square 2d array.") 

149 

150 if len(seq_of_zeros) == 0: 

151 return 1.0 

152 dt = seq_of_zeros.dtype 

153 a = ones((1,), dtype=dt) 

154 for zero in seq_of_zeros: 

155 a = NX.convolve(a, array([1, -zero], dtype=dt), mode='full') 

156 

157 if issubclass(a.dtype.type, NX.complexfloating): 

158 # if complex roots are all complex conjugates, the roots are real. 

159 roots = NX.asarray(seq_of_zeros, complex) 

160 if NX.all(NX.sort(roots) == NX.sort(roots.conjugate())): 

161 a = a.real.copy() 

162 

163 return a 

164 

165 

166def _roots_dispatcher(p): 

167 return p 

168 

169 

170@array_function_dispatch(_roots_dispatcher) 

171def roots(p): 

172 """ 

173 Return the roots of a polynomial with coefficients given in p. 

174 

175 .. note:: 

176 This forms part of the old polynomial API. Since version 1.4, the 

177 new polynomial API defined in `numpy.polynomial` is preferred. 

178 A summary of the differences can be found in the 

179 :doc:`transition guide </reference/routines.polynomials>`. 

180 

181 The values in the rank-1 array `p` are coefficients of a polynomial. 

182 If the length of `p` is n+1 then the polynomial is described by:: 

183 

184 p[0] * x**n + p[1] * x**(n-1) + ... + p[n-1]*x + p[n] 

185 

186 Parameters 

187 ---------- 

188 p : array_like 

189 Rank-1 array of polynomial coefficients. 

190 

191 Returns 

192 ------- 

193 out : ndarray 

194 An array containing the roots of the polynomial. 

195 

196 Raises 

197 ------ 

198 ValueError 

199 When `p` cannot be converted to a rank-1 array. 

200 

201 See also 

202 -------- 

203 poly : Find the coefficients of a polynomial with a given sequence 

204 of roots. 

205 polyval : Compute polynomial values. 

206 polyfit : Least squares polynomial fit. 

207 poly1d : A one-dimensional polynomial class. 

208 

209 Notes 

210 ----- 

211 The algorithm relies on computing the eigenvalues of the 

212 companion matrix [1]_. 

213 

214 References 

215 ---------- 

216 .. [1] R. A. Horn & C. R. Johnson, *Matrix Analysis*. Cambridge, UK: 

217 Cambridge University Press, 1999, pp. 146-7. 

218 

219 Examples 

220 -------- 

221 >>> import numpy as np 

222 >>> coeff = [3.2, 2, 1] 

223 >>> np.roots(coeff) 

224 array([-0.3125+0.46351241j, -0.3125-0.46351241j]) 

225 

226 """ 

227 # If input is scalar, this makes it an array 

228 p = atleast_1d(p) 

229 if p.ndim != 1: 

230 raise ValueError("Input must be a rank-1 array.") 

231 

232 # find non-zero array entries 

233 non_zero = NX.nonzero(NX.ravel(p))[0] 

234 

235 # Return an empty array if polynomial is all zeros 

236 if len(non_zero) == 0: 

237 return NX.array([]) 

238 

239 # find the number of trailing zeros -- this is the number of roots at 0. 

240 trailing_zeros = len(p) - non_zero[-1] - 1 

241 

242 # strip leading and trailing zeros 

243 p = p[int(non_zero[0]):int(non_zero[-1]) + 1] 

244 

245 # casting: if incoming array isn't floating point, make it floating point. 

246 if not issubclass(p.dtype.type, (NX.floating, NX.complexfloating)): 

247 p = p.astype(float) 

248 

249 N = len(p) 

250 if N > 1: 

251 # build companion matrix and find its eigenvalues (the roots) 

252 A = diag(NX.ones((N - 2,), p.dtype), -1) 

253 A[0, :] = -p[1:] / p[0] 

254 roots = eigvals(A) 

255 else: 

256 roots = NX.array([]) 

257 

258 # tack any zeros onto the back of the array 

259 roots = hstack((roots, NX.zeros(trailing_zeros, roots.dtype))) 

260 return roots 

261 

262 

263def _polyint_dispatcher(p, m=None, k=None): 

264 return (p,) 

265 

266 

267@array_function_dispatch(_polyint_dispatcher) 

268def polyint(p, m=1, k=None): 

269 """ 

270 Return an antiderivative (indefinite integral) of a polynomial. 

271 

272 .. note:: 

273 This forms part of the old polynomial API. Since version 1.4, the 

274 new polynomial API defined in `numpy.polynomial` is preferred. 

275 A summary of the differences can be found in the 

276 :doc:`transition guide </reference/routines.polynomials>`. 

277 

278 The returned order `m` antiderivative `P` of polynomial `p` satisfies 

279 :math:`\\frac{d^m}{dx^m}P(x) = p(x)` and is defined up to `m - 1` 

280 integration constants `k`. The constants determine the low-order 

281 polynomial part 

282 

283 .. math:: \\frac{k_{m-1}}{0!} x^0 + \\ldots + \\frac{k_0}{(m-1)!}x^{m-1} 

284 

285 of `P` so that :math:`P^{(j)}(0) = k_{m-j-1}`. 

286 

287 Parameters 

288 ---------- 

289 p : array_like or poly1d 

290 Polynomial to integrate. 

291 A sequence is interpreted as polynomial coefficients, see `poly1d`. 

292 m : int, optional 

293 Order of the antiderivative. (Default: 1) 

294 k : list of `m` scalars or scalar, optional 

295 Integration constants. They are given in the order of integration: 

296 those corresponding to highest-order terms come first. 

297 

298 If ``None`` (default), all constants are assumed to be zero. 

299 If `m = 1`, a single scalar can be given instead of a list. 

300 

301 See Also 

302 -------- 

303 polyder : derivative of a polynomial 

304 poly1d.integ : equivalent method 

305 

306 Examples 

307 -------- 

308 

309 The defining property of the antiderivative: 

310 

311 >>> import numpy as np 

312 

313 >>> p = np.poly1d([1,1,1]) 

314 >>> P = np.polyint(p) 

315 >>> P 

316 poly1d([ 0.33333333, 0.5 , 1. , 0. ]) # may vary 

317 >>> np.polyder(P) == p 

318 True 

319 

320 The integration constants default to zero, but can be specified: 

321 

322 >>> P = np.polyint(p, 3) 

323 >>> P(0) 

324 0.0 

325 >>> np.polyder(P)(0) 

326 0.0 

327 >>> np.polyder(P, 2)(0) 

328 0.0 

329 >>> P = np.polyint(p, 3, k=[6,5,3]) 

330 >>> P 

331 poly1d([ 0.01666667, 0.04166667, 0.16666667, 3. , 5. , 3. ]) # may vary 

332 

333 Note that 3 = 6 / 2!, and that the constants are given in the order of 

334 integrations. Constant of the highest-order polynomial term comes first: 

335 

336 >>> np.polyder(P, 2)(0) 

337 6.0 

338 >>> np.polyder(P, 1)(0) 

339 5.0 

340 >>> P(0) 

341 3.0 

342 

343 """ 

344 m = int(m) 

345 if m < 0: 

346 raise ValueError("Order of integral must be positive (see polyder)") 

347 if k is None: 

348 k = NX.zeros(m, float) 

349 k = atleast_1d(k) 

350 if len(k) == 1 and m > 1: 

351 k = k[0] * NX.ones(m, float) 

352 if len(k) < m: 

353 raise ValueError( 

354 "k must be a scalar or a rank-1 array of length 1 or >m.") 

355 

356 truepoly = isinstance(p, poly1d) 

357 p = NX.asarray(p) 

358 if m == 0: 

359 if truepoly: 

360 return poly1d(p) 

361 return p 

362 else: 

363 # Note: this must work also with object and integer arrays 

364 y = NX.concatenate((p.__truediv__(NX.arange(len(p), 0, -1)), [k[0]])) 

365 val = polyint(y, m - 1, k=k[1:]) 

366 if truepoly: 

367 return poly1d(val) 

368 return val 

369 

370 

371def _polyder_dispatcher(p, m=None): 

372 return (p,) 

373 

374 

375@array_function_dispatch(_polyder_dispatcher) 

376def polyder(p, m=1): 

377 """ 

378 Return the derivative of the specified order of a polynomial. 

379 

380 .. note:: 

381 This forms part of the old polynomial API. Since version 1.4, the 

382 new polynomial API defined in `numpy.polynomial` is preferred. 

383 A summary of the differences can be found in the 

384 :doc:`transition guide </reference/routines.polynomials>`. 

385 

386 Parameters 

387 ---------- 

388 p : poly1d or sequence 

389 Polynomial to differentiate. 

390 A sequence is interpreted as polynomial coefficients, see `poly1d`. 

391 m : int, optional 

392 Order of differentiation (default: 1) 

393 

394 Returns 

395 ------- 

396 der : poly1d 

397 A new polynomial representing the derivative. 

398 

399 See Also 

400 -------- 

401 polyint : Anti-derivative of a polynomial. 

402 poly1d : Class for one-dimensional polynomials. 

403 

404 Examples 

405 -------- 

406 

407 The derivative of the polynomial :math:`x^3 + x^2 + x^1 + 1` is: 

408 

409 >>> import numpy as np 

410 

411 >>> p = np.poly1d([1,1,1,1]) 

412 >>> p2 = np.polyder(p) 

413 >>> p2 

414 poly1d([3, 2, 1]) 

415 

416 which evaluates to: 

417 

418 >>> p2(2.) 

419 17.0 

420 

421 We can verify this, approximating the derivative with 

422 ``(f(x + h) - f(x))/h``: 

423 

424 >>> (p(2. + 0.001) - p(2.)) / 0.001 

425 17.007000999997857 

426 

427 The fourth-order derivative of a 3rd-order polynomial is zero: 

428 

429 >>> np.polyder(p, 2) 

430 poly1d([6, 2]) 

431 >>> np.polyder(p, 3) 

432 poly1d([6]) 

433 >>> np.polyder(p, 4) 

434 poly1d([0]) 

435 

436 """ 

437 m = int(m) 

438 if m < 0: 

439 raise ValueError("Order of derivative must be positive (see polyint)") 

440 

441 truepoly = isinstance(p, poly1d) 

442 p = NX.asarray(p) 

443 n = len(p) - 1 

444 y = p[:-1] * NX.arange(n, 0, -1) 

445 if m == 0: 

446 val = p 

447 else: 

448 val = polyder(y, m - 1) 

449 if truepoly: 

450 val = poly1d(val) 

451 return val 

452 

453 

454def _polyfit_dispatcher(x, y, deg, rcond=None, full=None, w=None, cov=None): 

455 return (x, y, w) 

456 

457 

458@array_function_dispatch(_polyfit_dispatcher) 

459def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False): 

460 """ 

461 Least squares polynomial fit. 

462 

463 .. note:: 

464 This forms part of the old polynomial API. Since version 1.4, the 

465 new polynomial API defined in `numpy.polynomial` is preferred. 

466 A summary of the differences can be found in the 

467 :doc:`transition guide </reference/routines.polynomials>`. 

468 

469 Fit a polynomial ``p[0] * x**deg + ... + p[deg]`` of degree `deg` 

470 to points `(x, y)`. Returns a vector of coefficients `p` that minimises 

471 the squared error in the order `deg`, `deg-1`, ... `0`. 

472 

473 The `Polynomial.fit <numpy.polynomial.polynomial.Polynomial.fit>` class 

474 method is recommended for new code as it is more stable numerically. See 

475 the documentation of the method for more information. 

476 

477 Parameters 

478 ---------- 

479 x : array_like, shape (M,) 

480 x-coordinates of the M sample points ``(x[i], y[i])``. 

481 y : array_like, shape (M,) or (M, K) 

482 y-coordinates of the sample points. Several data sets of sample 

483 points sharing the same x-coordinates can be fitted at once by 

484 passing in a 2D-array that contains one dataset per column. 

485 deg : int 

486 Degree of the fitting polynomial 

487 rcond : float, optional 

488 Relative condition number of the fit. Singular values smaller than 

489 this relative to the largest singular value will be ignored. The 

490 default value is len(x)*eps, where eps is the relative precision of 

491 the float type, about 2e-16 in most cases. 

492 full : bool, optional 

493 Switch determining nature of return value. When it is False (the 

494 default) just the coefficients are returned, when True diagnostic 

495 information from the singular value decomposition is also returned. 

496 w : array_like, shape (M,), optional 

497 Weights. If not None, the weight ``w[i]`` applies to the unsquared 

498 residual ``y[i] - y_hat[i]`` at ``x[i]``. Ideally the weights are 

499 chosen so that the errors of the products ``w[i]*y[i]`` all have the 

500 same variance. When using inverse-variance weighting, use 

501 ``w[i] = 1/sigma(y[i])``. The default value is None. 

502 cov : bool or str, optional 

503 If given and not `False`, return not just the estimate but also its 

504 covariance matrix. By default, the covariance are scaled by 

505 chi2/dof, where dof = M - (deg + 1), i.e., the weights are presumed 

506 to be unreliable except in a relative sense and everything is scaled 

507 such that the reduced chi2 is unity. This scaling is omitted if 

508 ``cov='unscaled'``, as is relevant for the case that the weights are 

509 w = 1/sigma, with sigma known to be a reliable estimate of the 

510 uncertainty. 

511 

512 Returns 

513 ------- 

514 p : ndarray, shape (deg + 1,) or (deg + 1, K) 

515 Polynomial coefficients, highest power first. If `y` was 2-D, the 

516 coefficients for `k`-th data set are in ``p[:,k]``. 

517 

518 residuals, rank, singular_values, rcond 

519 These values are only returned if ``full == True`` 

520 

521 - residuals -- sum of squared residuals of the least squares fit 

522 - rank -- the effective rank of the scaled Vandermonde 

523 coefficient matrix 

524 - singular_values -- singular values of the scaled Vandermonde 

525 coefficient matrix 

526 - rcond -- value of `rcond`. 

527 

528 For more details, see `numpy.linalg.lstsq`. 

529 

530 V : ndarray, shape (deg + 1, deg + 1) or (deg + 1, deg + 1, K) 

531 Present only if ``full == False`` and ``cov == True``. The covariance 

532 matrix of the polynomial coefficient estimates. The diagonal of 

533 this matrix are the variance estimates for each coefficient. If y 

534 is a 2-D array, then the covariance matrix for the `k`-th data set 

535 are in ``V[:,:,k]`` 

536 

537 

538 Warns 

539 ----- 

540 RankWarning 

541 The rank of the coefficient matrix in the least-squares fit is 

542 deficient. The warning is only raised if ``full == False``. 

543 

544 The warnings can be turned off by 

545 

546 >>> import warnings 

547 >>> warnings.simplefilter('ignore', np.exceptions.RankWarning) 

548 

549 See Also 

550 -------- 

551 polyval : Compute polynomial values. 

552 linalg.lstsq : Computes a least-squares fit. 

553 scipy.interpolate.UnivariateSpline : Computes spline fits. 

554 

555 Notes 

556 ----- 

557 The solution minimizes the squared error 

558 

559 .. math:: 

560 E = \\sum_{j=0}^k |p(x_j) - y_j|^2 

561 

562 in the equations:: 

563 

564 x[0]**n * p[0] + ... + x[0] * p[n-1] + p[n] = y[0] 

565 x[1]**n * p[0] + ... + x[1] * p[n-1] + p[n] = y[1] 

566 ... 

567 x[k]**n * p[0] + ... + x[k] * p[n-1] + p[n] = y[k] 

568 

569 The coefficient matrix of the coefficients `p` is a Vandermonde matrix. 

570 

571 `polyfit` issues a `~exceptions.RankWarning` when the least-squares fit is 

572 badly conditioned. This implies that the best fit is not well-defined due 

573 to numerical error. The results may be improved by lowering the polynomial 

574 degree or by replacing `x` by `x` - `x`.mean(). The `rcond` parameter 

575 can also be set to a value smaller than its default, but the resulting 

576 fit may be spurious: including contributions from the small singular 

577 values can add numerical noise to the result. 

578 

579 Note that fitting polynomial coefficients is inherently badly conditioned 

580 when the degree of the polynomial is large or the interval of sample points 

581 is badly centered. The quality of the fit should always be checked in these 

582 cases. When polynomial fits are not satisfactory, splines may be a good 

583 alternative. 

584 

585 References 

586 ---------- 

587 .. [1] Wikipedia, "Curve fitting", 

588 https://en.wikipedia.org/wiki/Curve_fitting 

589 .. [2] Wikipedia, "Polynomial interpolation", 

590 https://en.wikipedia.org/wiki/Polynomial_interpolation 

591 

592 Examples 

593 -------- 

594 >>> import numpy as np 

595 >>> import warnings 

596 >>> x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0]) 

597 >>> y = np.array([0.0, 0.8, 0.9, 0.1, -0.8, -1.0]) 

598 >>> z = np.polyfit(x, y, 3) 

599 >>> z 

600 array([ 0.08703704, -0.81349206, 1.69312169, -0.03968254]) # may vary 

601 

602 It is convenient to use `poly1d` objects for dealing with polynomials: 

603 

604 >>> p = np.poly1d(z) 

605 >>> p(0.5) 

606 0.6143849206349179 # may vary 

607 >>> p(3.5) 

608 -0.34732142857143039 # may vary 

609 >>> p(10) 

610 22.579365079365115 # may vary 

611 

612 High-order polynomials may oscillate wildly: 

613 

614 >>> with warnings.catch_warnings(): 

615 ... warnings.simplefilter('ignore', np.exceptions.RankWarning) 

616 ... p30 = np.poly1d(np.polyfit(x, y, 30)) 

617 ... 

618 >>> p30(4) 

619 -0.80000000000000204 # may vary 

620 >>> p30(5) 

621 -0.99999999999999445 # may vary 

622 >>> p30(4.5) 

623 -0.10547061179440398 # may vary 

624 

625 Illustration: 

626 

627 >>> import matplotlib.pyplot as plt 

628 >>> xp = np.linspace(-2, 6, 100) 

629 >>> _ = plt.plot(x, y, '.', xp, p(xp), '-', xp, p30(xp), '--') 

630 >>> plt.ylim(-2,2) 

631 (-2, 2) 

632 >>> plt.show() 

633 

634 """ 

635 order = int(deg) + 1 

636 x = NX.asarray(x) + 0.0 

637 y = NX.asarray(y) + 0.0 

638 

639 # check arguments. 

640 if deg < 0: 

641 raise ValueError("expected deg >= 0") 

642 if x.ndim != 1: 

643 raise TypeError("expected 1D vector for x") 

644 if x.size == 0: 

645 raise TypeError("expected non-empty vector for x") 

646 if y.ndim < 1 or y.ndim > 2: 

647 raise TypeError("expected 1D or 2D array for y") 

648 if x.shape[0] != y.shape[0]: 

649 raise TypeError("expected x and y to have same length") 

650 

651 # set rcond 

652 if rcond is None: 

653 rcond = len(x) * finfo(x.dtype).eps 

654 

655 # set up least squares equation for powers of x 

656 lhs = vander(x, order) 

657 rhs = y 

658 

659 # apply weighting 

660 if w is not None: 

661 w = NX.asarray(w) + 0.0 

662 if w.ndim != 1: 

663 raise TypeError("expected a 1-d array for weights") 

664 if w.shape[0] != y.shape[0]: 

665 raise TypeError("expected w and y to have the same length") 

666 lhs *= w[:, NX.newaxis] 

667 if rhs.ndim == 2: 

668 rhs *= w[:, NX.newaxis] 

669 else: 

670 rhs *= w 

671 

672 # scale lhs to improve condition number and solve 

673 scale = NX.sqrt((lhs * lhs).sum(axis=0)) 

674 lhs /= scale 

675 c, resids, rank, s = lstsq(lhs, rhs, rcond) 

676 c = (c.T / scale).T # broadcast scale coefficients 

677 

678 # warn on rank reduction, which indicates an ill conditioned matrix 

679 if rank != order and not full: 

680 msg = "Polyfit may be poorly conditioned" 

681 warnings.warn(msg, RankWarning, stacklevel=2) 

682 

683 if full: 

684 return c, resids, rank, s, rcond 

685 elif cov: 

686 Vbase = inv(dot(lhs.T, lhs)) 

687 Vbase /= NX.outer(scale, scale) 

688 if cov == "unscaled": 

689 fac = 1 

690 else: 

691 if len(x) <= order: 

692 raise ValueError("the number of data points must exceed order " 

693 "to scale the covariance matrix") 

694 # note, this used to be: fac = resids / (len(x) - order - 2.0) 

695 # it was decided that the "- 2" (originally justified by "Bayesian 

696 # uncertainty analysis") is not what the user expects 

697 # (see gh-11196 and gh-11197) 

698 fac = resids / (len(x) - order) 

699 if y.ndim == 1: 

700 return c, Vbase * fac 

701 else: 

702 return c, Vbase[:, :, NX.newaxis] * fac 

703 else: 

704 return c 

705 

706 

707def _polyval_dispatcher(p, x): 

708 return (p, x) 

709 

710 

711@array_function_dispatch(_polyval_dispatcher) 

712def polyval(p, x): 

713 """ 

714 Evaluate a polynomial at specific values. 

715 

716 .. note:: 

717 This forms part of the old polynomial API. Since version 1.4, the 

718 new polynomial API defined in `numpy.polynomial` is preferred. 

719 A summary of the differences can be found in the 

720 :doc:`transition guide </reference/routines.polynomials>`. 

721 

722 If `p` is of length N, this function returns the value:: 

723 

724 p[0]*x**(N-1) + p[1]*x**(N-2) + ... + p[N-2]*x + p[N-1] 

725 

726 If `x` is a sequence, then ``p(x)`` is returned for each element of ``x``. 

727 If `x` is another polynomial then the composite polynomial ``p(x(t))`` 

728 is returned. 

729 

730 Parameters 

731 ---------- 

732 p : array_like or poly1d object 

733 1D array of polynomial coefficients (including coefficients equal 

734 to zero) from highest degree to the constant term, or an 

735 instance of poly1d. 

736 x : array_like or poly1d object 

737 A number, an array of numbers, or an instance of poly1d, at 

738 which to evaluate `p`. 

739 

740 Returns 

741 ------- 

742 values : ndarray or poly1d 

743 If `x` is a poly1d instance, the result is the composition of the two 

744 polynomials, i.e., `x` is "substituted" in `p` and the simplified 

745 result is returned. In addition, the type of `x` - array_like or 

746 poly1d - governs the type of the output: `x` array_like => `values` 

747 array_like, `x` a poly1d object => `values` is also. 

748 

749 See Also 

750 -------- 

751 poly1d: A polynomial class. 

752 

753 Notes 

754 ----- 

755 Horner's scheme [1]_ is used to evaluate the polynomial. Even so, 

756 for polynomials of high degree the values may be inaccurate due to 

757 rounding errors. Use carefully. 

758 

759 If `x` is a subtype of `ndarray` the return value will be of the same type. 

760 

761 References 

762 ---------- 

763 .. [1] I. N. Bronshtein, K. A. Semendyayev, and K. A. Hirsch (Eng. 

764 trans. Ed.), *Handbook of Mathematics*, New York, Van Nostrand 

765 Reinhold Co., 1985, pg. 720. 

766 

767 Examples 

768 -------- 

769 >>> import numpy as np 

770 >>> np.polyval([3,0,1], 5) # 3 * 5**2 + 0 * 5**1 + 1 

771 76 

772 >>> np.polyval([3,0,1], np.poly1d(5)) 

773 poly1d([76]) 

774 >>> np.polyval(np.poly1d([3,0,1]), 5) 

775 76 

776 >>> np.polyval(np.poly1d([3,0,1]), np.poly1d(5)) 

777 poly1d([76]) 

778 

779 """ 

780 p = NX.asarray(p) 

781 if isinstance(x, poly1d): 

782 y = 0 

783 else: 

784 x = NX.asanyarray(x) 

785 y = NX.zeros_like(x) 

786 for pv in p: 

787 y = y * x + pv 

788 return y 

789 

790 

791def _binary_op_dispatcher(a1, a2): 

792 return (a1, a2) 

793 

794 

795@array_function_dispatch(_binary_op_dispatcher) 

796def polyadd(a1, a2): 

797 """ 

798 Find the sum of two polynomials. 

799 

800 .. note:: 

801 This forms part of the old polynomial API. Since version 1.4, the 

802 new polynomial API defined in `numpy.polynomial` is preferred. 

803 A summary of the differences can be found in the 

804 :doc:`transition guide </reference/routines.polynomials>`. 

805 

806 Returns the polynomial resulting from the sum of two input polynomials. 

807 Each input must be either a poly1d object or a 1D sequence of polynomial 

808 coefficients, from highest to lowest degree. 

809 

810 Parameters 

811 ---------- 

812 a1, a2 : array_like or poly1d object 

813 Input polynomials. 

814 

815 Returns 

816 ------- 

817 out : ndarray or poly1d object 

818 The sum of the inputs. If either input is a poly1d object, then the 

819 output is also a poly1d object. Otherwise, it is a 1D array of 

820 polynomial coefficients from highest to lowest degree. 

821 

822 See Also 

823 -------- 

824 poly1d : A one-dimensional polynomial class. 

825 poly, polyadd, polyder, polydiv, polyfit, polyint, polysub, polyval 

826 

827 Examples 

828 -------- 

829 >>> import numpy as np 

830 >>> np.polyadd([1, 2], [9, 5, 4]) 

831 array([9, 6, 6]) 

832 

833 Using poly1d objects: 

834 

835 >>> p1 = np.poly1d([1, 2]) 

836 >>> p2 = np.poly1d([9, 5, 4]) 

837 >>> print(p1) 

838 1 x + 2 

839 >>> print(p2) 

840 2 

841 9 x + 5 x + 4 

842 >>> print(np.polyadd(p1, p2)) 

843 2 

844 9 x + 6 x + 6 

845 

846 """ 

847 truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d)) 

848 a1 = atleast_1d(a1) 

849 a2 = atleast_1d(a2) 

850 diff = len(a2) - len(a1) 

851 if diff == 0: 

852 val = a1 + a2 

853 elif diff > 0: 

854 zr = NX.zeros(diff, a1.dtype) 

855 val = NX.concatenate((zr, a1)) + a2 

856 else: 

857 zr = NX.zeros(abs(diff), a2.dtype) 

858 val = a1 + NX.concatenate((zr, a2)) 

859 if truepoly: 

860 val = poly1d(val) 

861 return val 

862 

863 

864@array_function_dispatch(_binary_op_dispatcher) 

865def polysub(a1, a2): 

866 """ 

867 Difference (subtraction) of two polynomials. 

868 

869 .. note:: 

870 This forms part of the old polynomial API. Since version 1.4, the 

871 new polynomial API defined in `numpy.polynomial` is preferred. 

872 A summary of the differences can be found in the 

873 :doc:`transition guide </reference/routines.polynomials>`. 

874 

875 Given two polynomials `a1` and `a2`, returns ``a1 - a2``. 

876 `a1` and `a2` can be either array_like sequences of the polynomials' 

877 coefficients (including coefficients equal to zero), or `poly1d` objects. 

878 

879 Parameters 

880 ---------- 

881 a1, a2 : array_like or poly1d 

882 Minuend and subtrahend polynomials, respectively. 

883 

884 Returns 

885 ------- 

886 out : ndarray or poly1d 

887 Array or `poly1d` object of the difference polynomial's coefficients. 

888 

889 See Also 

890 -------- 

891 polyval, polydiv, polymul, polyadd 

892 

893 Examples 

894 -------- 

895 

896 .. math:: (2 x^2 + 10 x - 2) - (3 x^2 + 10 x -4) = (-x^2 + 2) 

897 

898 >>> import numpy as np 

899 

900 >>> np.polysub([2, 10, -2], [3, 10, -4]) 

901 array([-1, 0, 2]) 

902 

903 """ 

904 truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d)) 

905 a1 = atleast_1d(a1) 

906 a2 = atleast_1d(a2) 

907 diff = len(a2) - len(a1) 

908 if diff == 0: 

909 val = a1 - a2 

910 elif diff > 0: 

911 zr = NX.zeros(diff, a1.dtype) 

912 val = NX.concatenate((zr, a1)) - a2 

913 else: 

914 zr = NX.zeros(abs(diff), a2.dtype) 

915 val = a1 - NX.concatenate((zr, a2)) 

916 if truepoly: 

917 val = poly1d(val) 

918 return val 

919 

920 

921@array_function_dispatch(_binary_op_dispatcher) 

922def polymul(a1, a2): 

923 """ 

924 Find the product of two polynomials. 

925 

926 .. note:: 

927 This forms part of the old polynomial API. Since version 1.4, the 

928 new polynomial API defined in `numpy.polynomial` is preferred. 

929 A summary of the differences can be found in the 

930 :doc:`transition guide </reference/routines.polynomials>`. 

931 

932 Finds the polynomial resulting from the multiplication of the two input 

933 polynomials. Each input must be either a poly1d object or a 1D sequence 

934 of polynomial coefficients, from highest to lowest degree. 

935 

936 Parameters 

937 ---------- 

938 a1, a2 : array_like or poly1d object 

939 Input polynomials. 

940 

941 Returns 

942 ------- 

943 out : ndarray or poly1d object 

944 The polynomial resulting from the multiplication of the inputs. If 

945 either inputs is a poly1d object, then the output is also a poly1d 

946 object. Otherwise, it is a 1D array of polynomial coefficients from 

947 highest to lowest degree. 

948 

949 See Also 

950 -------- 

951 poly1d : A one-dimensional polynomial class. 

952 poly, polyadd, polyder, polydiv, polyfit, polyint, polysub, polyval 

953 convolve : Array convolution. Same output as polymul, but has parameter 

954 for overlap mode. 

955 

956 Examples 

957 -------- 

958 >>> import numpy as np 

959 >>> np.polymul([1, 2, 3], [9, 5, 1]) 

960 array([ 9, 23, 38, 17, 3]) 

961 

962 Using poly1d objects: 

963 

964 >>> p1 = np.poly1d([1, 2, 3]) 

965 >>> p2 = np.poly1d([9, 5, 1]) 

966 >>> print(p1) 

967 2 

968 1 x + 2 x + 3 

969 >>> print(p2) 

970 2 

971 9 x + 5 x + 1 

972 >>> print(np.polymul(p1, p2)) 

973 4 3 2 

974 9 x + 23 x + 38 x + 17 x + 3 

975 

976 """ 

977 truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d)) 

978 a1, a2 = poly1d(a1), poly1d(a2) 

979 val = NX.convolve(a1, a2) 

980 if truepoly: 

981 val = poly1d(val) 

982 return val 

983 

984 

985def _polydiv_dispatcher(u, v): 

986 return (u, v) 

987 

988 

989@array_function_dispatch(_polydiv_dispatcher) 

990def polydiv(u, v): 

991 """ 

992 Returns the quotient and remainder of polynomial division. 

993 

994 .. note:: 

995 This forms part of the old polynomial API. Since version 1.4, the 

996 new polynomial API defined in `numpy.polynomial` is preferred. 

997 A summary of the differences can be found in the 

998 :doc:`transition guide </reference/routines.polynomials>`. 

999 

1000 The input arrays are the coefficients (including any coefficients 

1001 equal to zero) of the "numerator" (dividend) and "denominator" 

1002 (divisor) polynomials, respectively. 

1003 

1004 Parameters 

1005 ---------- 

1006 u : array_like or poly1d 

1007 Dividend polynomial's coefficients. 

1008 

1009 v : array_like or poly1d 

1010 Divisor polynomial's coefficients. 

1011 

1012 Returns 

1013 ------- 

1014 q : ndarray 

1015 Coefficients, including those equal to zero, of the quotient. 

1016 r : ndarray 

1017 Coefficients, including those equal to zero, of the remainder. 

1018 

1019 See Also 

1020 -------- 

1021 poly, polyadd, polyder, polydiv, polyfit, polyint, polymul, polysub 

1022 polyval 

1023 

1024 Notes 

1025 ----- 

1026 Both `u` and `v` must be 0-d or 1-d (ndim = 0 or 1), but `u.ndim` need 

1027 not equal `v.ndim`. In other words, all four possible combinations - 

1028 ``u.ndim = v.ndim = 0``, ``u.ndim = v.ndim = 1``, 

1029 ``u.ndim = 1, v.ndim = 0``, and ``u.ndim = 0, v.ndim = 1`` - work. 

1030 

1031 Examples 

1032 -------- 

1033 

1034 .. math:: \\frac{3x^2 + 5x + 2}{2x + 1} = 1.5x + 1.75, remainder 0.25 

1035 

1036 >>> import numpy as np 

1037 

1038 >>> x = np.array([3.0, 5.0, 2.0]) 

1039 >>> y = np.array([2.0, 1.0]) 

1040 >>> np.polydiv(x, y) 

1041 (array([1.5 , 1.75]), array([0.25])) 

1042 

1043 """ 

1044 truepoly = (isinstance(u, poly1d) or isinstance(v, poly1d)) 

1045 u = atleast_1d(u) + 0.0 

1046 v = atleast_1d(v) + 0.0 

1047 # w has the common type 

1048 w = u[0] + v[0] 

1049 m = len(u) - 1 

1050 n = len(v) - 1 

1051 scale = 1. / v[0] 

1052 q = NX.zeros((max(m - n + 1, 1),), w.dtype) 

1053 r = u.astype(w.dtype) 

1054 for k in range(m - n + 1): 

1055 d = scale * r[k] 

1056 q[k] = d 

1057 r[k:k + n + 1] -= d * v 

1058 while NX.allclose(r[0], 0, rtol=1e-14) and (r.shape[-1] > 1): 

1059 r = r[1:] 

1060 if truepoly: 

1061 return poly1d(q), poly1d(r) 

1062 return q, r 

1063 

1064 

1065_poly_mat = re.compile(r"\*\*([0-9]*)") 

1066def _raise_power(astr, wrap=70): 

1067 n = 0 

1068 line1 = '' 

1069 line2 = '' 

1070 output = ' ' 

1071 while True: 

1072 mat = _poly_mat.search(astr, n) 

1073 if mat is None: 

1074 break 

1075 span = mat.span() 

1076 power = mat.groups()[0] 

1077 partstr = astr[n:span[0]] 

1078 n = span[1] 

1079 toadd2 = partstr + ' ' * (len(power) - 1) 

1080 toadd1 = ' ' * (len(partstr) - 1) + power 

1081 if ((len(line2) + len(toadd2) > wrap) or 

1082 (len(line1) + len(toadd1) > wrap)): 

1083 output += line1 + "\n" + line2 + "\n " 

1084 line1 = toadd1 

1085 line2 = toadd2 

1086 else: 

1087 line2 += partstr + ' ' * (len(power) - 1) 

1088 line1 += ' ' * (len(partstr) - 1) + power 

1089 output += line1 + "\n" + line2 

1090 return output + astr[n:] 

1091 

1092 

1093@set_module('numpy') 

1094class poly1d: 

1095 """ 

1096 A one-dimensional polynomial class. 

1097 

1098 .. note:: 

1099 This forms part of the old polynomial API. Since version 1.4, the 

1100 new polynomial API defined in `numpy.polynomial` is preferred. 

1101 A summary of the differences can be found in the 

1102 :doc:`transition guide </reference/routines.polynomials>`. 

1103 

1104 A convenience class, used to encapsulate "natural" operations on 

1105 polynomials so that said operations may take on their customary 

1106 form in code (see Examples). 

1107 

1108 Parameters 

1109 ---------- 

1110 c_or_r : array_like 

1111 The polynomial's coefficients, in decreasing powers, or if 

1112 the value of the second parameter is True, the polynomial's 

1113 roots (values where the polynomial evaluates to 0). For example, 

1114 ``poly1d([1, 2, 3])`` returns an object that represents 

1115 :math:`x^2 + 2x + 3`, whereas ``poly1d([1, 2, 3], True)`` returns 

1116 one that represents :math:`(x-1)(x-2)(x-3) = x^3 - 6x^2 + 11x -6`. 

1117 r : bool, optional 

1118 If True, `c_or_r` specifies the polynomial's roots; the default 

1119 is False. 

1120 variable : str, optional 

1121 Changes the variable used when printing `p` from `x` to `variable` 

1122 (see Examples). 

1123 

1124 Examples 

1125 -------- 

1126 >>> import numpy as np 

1127 

1128 Construct the polynomial :math:`x^2 + 2x + 3`: 

1129 

1130 >>> import numpy as np 

1131 

1132 >>> p = np.poly1d([1, 2, 3]) 

1133 >>> print(np.poly1d(p)) 

1134 2 

1135 1 x + 2 x + 3 

1136 

1137 Evaluate the polynomial at :math:`x = 0.5`: 

1138 

1139 >>> p(0.5) 

1140 4.25 

1141 

1142 Find the roots: 

1143 

1144 >>> p.r 

1145 array([-1.+1.41421356j, -1.-1.41421356j]) 

1146 >>> p(p.r) 

1147 array([ -4.44089210e-16+0.j, -4.44089210e-16+0.j]) # may vary 

1148 

1149 These numbers in the previous line represent (0, 0) to machine precision 

1150 

1151 Show the coefficients: 

1152 

1153 >>> p.c 

1154 array([1, 2, 3]) 

1155 

1156 Display the order (the leading zero-coefficients are removed): 

1157 

1158 >>> p.order 

1159 2 

1160 

1161 Show the coefficient of the k-th power in the polynomial 

1162 (which is equivalent to ``p.c[-(i+1)]``): 

1163 

1164 >>> p[1] 

1165 2 

1166 

1167 Polynomials can be added, subtracted, multiplied, and divided 

1168 (returns quotient and remainder): 

1169 

1170 >>> p * p 

1171 poly1d([ 1, 4, 10, 12, 9]) 

1172 

1173 >>> (p**3 + 4) / p 

1174 (poly1d([ 1., 4., 10., 12., 9.]), poly1d([4.])) 

1175 

1176 ``asarray(p)`` gives the coefficient array, so polynomials can be 

1177 used in all functions that accept arrays: 

1178 

1179 >>> p**2 # square of polynomial 

1180 poly1d([ 1, 4, 10, 12, 9]) 

1181 

1182 >>> np.square(p) # square of individual coefficients 

1183 array([1, 4, 9]) 

1184 

1185 The variable used in the string representation of `p` can be modified, 

1186 using the `variable` parameter: 

1187 

1188 >>> p = np.poly1d([1,2,3], variable='z') 

1189 >>> print(p) 

1190 2 

1191 1 z + 2 z + 3 

1192 

1193 Construct a polynomial from its roots: 

1194 

1195 >>> np.poly1d([1, 2], True) 

1196 poly1d([ 1., -3., 2.]) 

1197 

1198 This is the same polynomial as obtained by: 

1199 

1200 >>> np.poly1d([1, -1]) * np.poly1d([1, -2]) 

1201 poly1d([ 1, -3, 2]) 

1202 

1203 """ 

1204 __hash__ = None 

1205 

1206 @property 

1207 def coeffs(self): 

1208 """ The polynomial coefficients """ 

1209 return self._coeffs 

1210 

1211 @coeffs.setter 

1212 def coeffs(self, value): 

1213 # allowing this makes p.coeffs *= 2 legal 

1214 if value is not self._coeffs: 

1215 raise AttributeError("Cannot set attribute") 

1216 

1217 @property 

1218 def variable(self): 

1219 """ The name of the polynomial variable """ 

1220 return self._variable 

1221 

1222 # calculated attributes 

1223 @property 

1224 def order(self): 

1225 """ The order or degree of the polynomial """ 

1226 return len(self._coeffs) - 1 

1227 

1228 @property 

1229 def roots(self): 

1230 """ The roots of the polynomial, where self(x) == 0 """ 

1231 return roots(self._coeffs) 

1232 

1233 # our internal _coeffs property need to be backed by __dict__['coeffs'] for 

1234 # scipy to work correctly. 

1235 @property 

1236 def _coeffs(self): 

1237 return self.__dict__['coeffs'] 

1238 

1239 @_coeffs.setter 

1240 def _coeffs(self, coeffs): 

1241 self.__dict__['coeffs'] = coeffs 

1242 

1243 # alias attributes 

1244 r = roots 

1245 c = coef = coefficients = coeffs 

1246 o = order 

1247 

1248 def __init__(self, c_or_r, r=False, variable=None): 

1249 if isinstance(c_or_r, poly1d): 

1250 self._variable = c_or_r._variable 

1251 self._coeffs = c_or_r._coeffs 

1252 

1253 if set(c_or_r.__dict__) - set(self.__dict__): 

1254 msg = ("In the future extra properties will not be copied " 

1255 "across when constructing one poly1d from another") 

1256 warnings.warn(msg, FutureWarning, stacklevel=2) 

1257 self.__dict__.update(c_or_r.__dict__) 

1258 

1259 if variable is not None: 

1260 self._variable = variable 

1261 return 

1262 if r: 

1263 c_or_r = poly(c_or_r) 

1264 c_or_r = atleast_1d(c_or_r) 

1265 if c_or_r.ndim > 1: 

1266 raise ValueError("Polynomial must be 1d only.") 

1267 c_or_r = trim_zeros(c_or_r, trim='f') 

1268 if len(c_or_r) == 0: 

1269 c_or_r = NX.array([0], dtype=c_or_r.dtype) 

1270 self._coeffs = c_or_r 

1271 if variable is None: 

1272 variable = 'x' 

1273 self._variable = variable 

1274 

1275 def __array__(self, t=None, copy=None): 

1276 if t: 

1277 return NX.asarray(self.coeffs, t, copy=copy) 

1278 else: 

1279 return NX.asarray(self.coeffs, copy=copy) 

1280 

1281 def __repr__(self): 

1282 vals = repr(self.coeffs) 

1283 vals = vals[6:-1] 

1284 return f"poly1d({vals})" 

1285 

1286 def __len__(self): 

1287 return self.order 

1288 

1289 def __str__(self): 

1290 thestr = "0" 

1291 var = self.variable 

1292 

1293 # Remove leading zeros 

1294 coeffs = self.coeffs[NX.logical_or.accumulate(self.coeffs != 0)] 

1295 N = len(coeffs) - 1 

1296 

1297 def fmt_float(q): 

1298 s = f'{q:.4g}' 

1299 s = s.removesuffix('.0000') 

1300 return s 

1301 

1302 for k, coeff in enumerate(coeffs): 

1303 if not iscomplex(coeff): 

1304 coefstr = fmt_float(real(coeff)) 

1305 elif real(coeff) == 0: 

1306 coefstr = f'{fmt_float(imag(coeff))}j' 

1307 else: 

1308 coefstr = f'({fmt_float(real(coeff))} + {fmt_float(imag(coeff))}j)' 

1309 

1310 power = (N - k) 

1311 if power == 0: 

1312 if coefstr != '0': 

1313 newstr = f'{coefstr}' 

1314 elif k == 0: 

1315 newstr = '0' 

1316 else: 

1317 newstr = '' 

1318 elif power == 1: 

1319 if coefstr == '0': 

1320 newstr = '' 

1321 elif coefstr == 'b': 

1322 newstr = var 

1323 else: 

1324 newstr = f'{coefstr} {var}' 

1325 elif coefstr == '0': 

1326 newstr = '' 

1327 elif coefstr == 'b': 

1328 newstr = '%s**%d' % (var, power,) 

1329 else: 

1330 newstr = '%s %s**%d' % (coefstr, var, power) 

1331 

1332 if k > 0: 

1333 if newstr != '': 

1334 if newstr.startswith('-'): 

1335 thestr = f"{thestr} - {newstr[1:]}" 

1336 else: 

1337 thestr = f"{thestr} + {newstr}" 

1338 else: 

1339 thestr = newstr 

1340 return _raise_power(thestr) 

1341 

1342 def __call__(self, val): 

1343 return polyval(self.coeffs, val) 

1344 

1345 def __neg__(self): 

1346 return poly1d(-self.coeffs) 

1347 

1348 def __pos__(self): 

1349 return self 

1350 

1351 def __mul__(self, other): 

1352 if isscalar(other): 

1353 return poly1d(self.coeffs * other) 

1354 else: 

1355 other = poly1d(other) 

1356 return poly1d(polymul(self.coeffs, other.coeffs)) 

1357 

1358 def __rmul__(self, other): 

1359 if isscalar(other): 

1360 return poly1d(other * self.coeffs) 

1361 else: 

1362 other = poly1d(other) 

1363 return poly1d(polymul(self.coeffs, other.coeffs)) 

1364 

1365 def __add__(self, other): 

1366 other = poly1d(other) 

1367 return poly1d(polyadd(self.coeffs, other.coeffs)) 

1368 

1369 def __radd__(self, other): 

1370 other = poly1d(other) 

1371 return poly1d(polyadd(self.coeffs, other.coeffs)) 

1372 

1373 def __pow__(self, val): 

1374 if not isscalar(val) or int(val) != val or val < 0: 

1375 raise ValueError("Power to non-negative integers only.") 

1376 res = [1] 

1377 for _ in range(val): 

1378 res = polymul(self.coeffs, res) 

1379 return poly1d(res) 

1380 

1381 def __sub__(self, other): 

1382 other = poly1d(other) 

1383 return poly1d(polysub(self.coeffs, other.coeffs)) 

1384 

1385 def __rsub__(self, other): 

1386 other = poly1d(other) 

1387 return poly1d(polysub(other.coeffs, self.coeffs)) 

1388 

1389 def __truediv__(self, other): 

1390 if isscalar(other): 

1391 return poly1d(self.coeffs / other) 

1392 else: 

1393 other = poly1d(other) 

1394 return polydiv(self, other) 

1395 

1396 def __rtruediv__(self, other): 

1397 if isscalar(other): 

1398 return poly1d(other / self.coeffs) 

1399 else: 

1400 other = poly1d(other) 

1401 return polydiv(other, self) 

1402 

1403 def __eq__(self, other): 

1404 if not isinstance(other, poly1d): 

1405 return NotImplemented 

1406 if self.coeffs.shape != other.coeffs.shape: 

1407 return False 

1408 return (self.coeffs == other.coeffs).all() 

1409 

1410 def __ne__(self, other): 

1411 if not isinstance(other, poly1d): 

1412 return NotImplemented 

1413 return not self.__eq__(other) 

1414 

1415 def __getitem__(self, val): 

1416 ind = self.order - val 

1417 if val > self.order: 

1418 return self.coeffs.dtype.type(0) 

1419 if val < 0: 

1420 return self.coeffs.dtype.type(0) 

1421 return self.coeffs[ind] 

1422 

1423 def __setitem__(self, key, val): 

1424 ind = self.order - key 

1425 if key < 0: 

1426 raise ValueError("Does not support negative powers.") 

1427 if key > self.order: 

1428 zr = NX.zeros(key - self.order, self.coeffs.dtype) 

1429 self._coeffs = NX.concatenate((zr, self.coeffs)) 

1430 ind = 0 

1431 self._coeffs[ind] = val 

1432 

1433 def __iter__(self): 

1434 return iter(self.coeffs) 

1435 

1436 def integ(self, m=1, k=0): 

1437 """ 

1438 Return an antiderivative (indefinite integral) of this polynomial. 

1439 

1440 Refer to `polyint` for full documentation. 

1441 

1442 See Also 

1443 -------- 

1444 polyint : equivalent function 

1445 

1446 """ 

1447 return poly1d(polyint(self.coeffs, m=m, k=k)) 

1448 

1449 def deriv(self, m=1): 

1450 """ 

1451 Return a derivative of this polynomial. 

1452 

1453 Refer to `polyder` for full documentation. 

1454 

1455 See Also 

1456 -------- 

1457 polyder : equivalent function 

1458 

1459 """ 

1460 return poly1d(polyder(self.coeffs, m=m)) 

1461 

1462# Stuff to do on module import 

1463 

1464 

1465warnings.simplefilter('always', RankWarning)