Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2Abstract base class for the various polynomial Classes. 

3 

4The ABCPolyBase class provides the methods needed to implement the common API 

5for the various polynomial classes. It operates as a mixin, but uses the 

6abc module from the stdlib, hence it is only available for Python >= 2.6. 

7 

8""" 

9import abc 

10import numbers 

11 

12import numpy as np 

13from . import polyutils as pu 

14 

15__all__ = ['ABCPolyBase'] 

16 

17class ABCPolyBase(abc.ABC): 

18 """An abstract base class for immutable series classes. 

19 

20 ABCPolyBase provides the standard Python numerical methods 

21 '+', '-', '*', '//', '%', 'divmod', '**', and '()' along with the 

22 methods listed below. 

23 

24 .. versionadded:: 1.9.0 

25 

26 Parameters 

27 ---------- 

28 coef : array_like 

29 Series coefficients in order of increasing degree, i.e., 

30 ``(1, 2, 3)`` gives ``1*P_0(x) + 2*P_1(x) + 3*P_2(x)``, where 

31 ``P_i`` is the basis polynomials of degree ``i``. 

32 domain : (2,) array_like, optional 

33 Domain to use. The interval ``[domain[0], domain[1]]`` is mapped 

34 to the interval ``[window[0], window[1]]`` by shifting and scaling. 

35 The default value is the derived class domain. 

36 window : (2,) array_like, optional 

37 Window, see domain for its use. The default value is the 

38 derived class window. 

39 

40 Attributes 

41 ---------- 

42 coef : (N,) ndarray 

43 Series coefficients in order of increasing degree. 

44 domain : (2,) ndarray 

45 Domain that is mapped to window. 

46 window : (2,) ndarray 

47 Window that domain is mapped to. 

48 

49 Class Attributes 

50 ---------------- 

51 maxpower : int 

52 Maximum power allowed, i.e., the largest number ``n`` such that 

53 ``p(x)**n`` is allowed. This is to limit runaway polynomial size. 

54 domain : (2,) ndarray 

55 Default domain of the class. 

56 window : (2,) ndarray 

57 Default window of the class. 

58 

59 """ 

60 

61 # Not hashable 

62 __hash__ = None 

63 

64 # Opt out of numpy ufuncs and Python ops with ndarray subclasses. 

65 __array_ufunc__ = None 

66 

67 # Limit runaway size. T_n^m has degree n*m 

68 maxpower = 100 

69 

70 @property 

71 @abc.abstractmethod 

72 def domain(self): 

73 pass 

74 

75 @property 

76 @abc.abstractmethod 

77 def window(self): 

78 pass 

79 

80 @property 

81 @abc.abstractmethod 

82 def nickname(self): 

83 pass 

84 

85 @property 

86 @abc.abstractmethod 

87 def basis_name(self): 

88 pass 

89 

90 @staticmethod 

91 @abc.abstractmethod 

92 def _add(c1, c2): 

93 pass 

94 

95 @staticmethod 

96 @abc.abstractmethod 

97 def _sub(c1, c2): 

98 pass 

99 

100 @staticmethod 

101 @abc.abstractmethod 

102 def _mul(c1, c2): 

103 pass 

104 

105 @staticmethod 

106 @abc.abstractmethod 

107 def _div(c1, c2): 

108 pass 

109 

110 @staticmethod 

111 @abc.abstractmethod 

112 def _pow(c, pow, maxpower=None): 

113 pass 

114 

115 @staticmethod 

116 @abc.abstractmethod 

117 def _val(x, c): 

118 pass 

119 

120 @staticmethod 

121 @abc.abstractmethod 

122 def _int(c, m, k, lbnd, scl): 

123 pass 

124 

125 @staticmethod 

126 @abc.abstractmethod 

127 def _der(c, m, scl): 

128 pass 

129 

130 @staticmethod 

131 @abc.abstractmethod 

132 def _fit(x, y, deg, rcond, full): 

133 pass 

134 

135 @staticmethod 

136 @abc.abstractmethod 

137 def _line(off, scl): 

138 pass 

139 

140 @staticmethod 

141 @abc.abstractmethod 

142 def _roots(c): 

143 pass 

144 

145 @staticmethod 

146 @abc.abstractmethod 

147 def _fromroots(r): 

148 pass 

149 

150 def has_samecoef(self, other): 

151 """Check if coefficients match. 

152 

153 .. versionadded:: 1.6.0 

154 

155 Parameters 

156 ---------- 

157 other : class instance 

158 The other class must have the ``coef`` attribute. 

159 

160 Returns 

161 ------- 

162 bool : boolean 

163 True if the coefficients are the same, False otherwise. 

164 

165 """ 

166 if len(self.coef) != len(other.coef): 

167 return False 

168 elif not np.all(self.coef == other.coef): 

169 return False 

170 else: 

171 return True 

172 

173 def has_samedomain(self, other): 

174 """Check if domains match. 

175 

176 .. versionadded:: 1.6.0 

177 

178 Parameters 

179 ---------- 

180 other : class instance 

181 The other class must have the ``domain`` attribute. 

182 

183 Returns 

184 ------- 

185 bool : boolean 

186 True if the domains are the same, False otherwise. 

187 

188 """ 

189 return np.all(self.domain == other.domain) 

190 

191 def has_samewindow(self, other): 

192 """Check if windows match. 

193 

194 .. versionadded:: 1.6.0 

195 

196 Parameters 

197 ---------- 

198 other : class instance 

199 The other class must have the ``window`` attribute. 

200 

201 Returns 

202 ------- 

203 bool : boolean 

204 True if the windows are the same, False otherwise. 

205 

206 """ 

207 return np.all(self.window == other.window) 

208 

209 def has_sametype(self, other): 

210 """Check if types match. 

211 

212 .. versionadded:: 1.7.0 

213 

214 Parameters 

215 ---------- 

216 other : object 

217 Class instance. 

218 

219 Returns 

220 ------- 

221 bool : boolean 

222 True if other is same class as self 

223 

224 """ 

225 return isinstance(other, self.__class__) 

226 

227 def _get_coefficients(self, other): 

228 """Interpret other as polynomial coefficients. 

229 

230 The `other` argument is checked to see if it is of the same 

231 class as self with identical domain and window. If so, 

232 return its coefficients, otherwise return `other`. 

233 

234 .. versionadded:: 1.9.0 

235 

236 Parameters 

237 ---------- 

238 other : anything 

239 Object to be checked. 

240 

241 Returns 

242 ------- 

243 coef 

244 The coefficients of`other` if it is a compatible instance, 

245 of ABCPolyBase, otherwise `other`. 

246 

247 Raises 

248 ------ 

249 TypeError 

250 When `other` is an incompatible instance of ABCPolyBase. 

251 

252 """ 

253 if isinstance(other, ABCPolyBase): 

254 if not isinstance(other, self.__class__): 

255 raise TypeError("Polynomial types differ") 

256 elif not np.all(self.domain == other.domain): 

257 raise TypeError("Domains differ") 

258 elif not np.all(self.window == other.window): 

259 raise TypeError("Windows differ") 

260 return other.coef 

261 return other 

262 

263 def __init__(self, coef, domain=None, window=None): 

264 [coef] = pu.as_series([coef], trim=False) 

265 self.coef = coef 

266 

267 if domain is not None: 

268 [domain] = pu.as_series([domain], trim=False) 

269 if len(domain) != 2: 

270 raise ValueError("Domain has wrong number of elements.") 

271 self.domain = domain 

272 

273 if window is not None: 

274 [window] = pu.as_series([window], trim=False) 

275 if len(window) != 2: 

276 raise ValueError("Window has wrong number of elements.") 

277 self.window = window 

278 

279 def __repr__(self): 

280 coef = repr(self.coef)[6:-1] 

281 domain = repr(self.domain)[6:-1] 

282 window = repr(self.window)[6:-1] 

283 name = self.__class__.__name__ 

284 return f"{name}({coef}, domain={domain}, window={window})" 

285 

286 def __str__(self): 

287 coef = str(self.coef) 

288 name = self.nickname 

289 return f"{name}({coef})" 

290 

291 @classmethod 

292 def _repr_latex_term(cls, i, arg_str, needs_parens): 

293 if cls.basis_name is None: 

294 raise NotImplementedError( 

295 "Subclasses must define either a basis name, or override " 

296 "_repr_latex_term(i, arg_str, needs_parens)") 

297 # since we always add parens, we don't care if the expression needs them 

298 return f"{{{cls.basis_name}}}_{{{i}}}({arg_str})" 

299 

300 @staticmethod 

301 def _repr_latex_scalar(x): 

302 # TODO: we're stuck with disabling math formatting until we handle 

303 # exponents in this function 

304 return r'\text{{{}}}'.format(x) 

305 

306 def _repr_latex_(self): 

307 # get the scaled argument string to the basis functions 

308 off, scale = self.mapparms() 

309 if off == 0 and scale == 1: 

310 term = 'x' 

311 needs_parens = False 

312 elif scale == 1: 

313 term = f"{self._repr_latex_scalar(off)} + x" 

314 needs_parens = True 

315 elif off == 0: 

316 term = f"{self._repr_latex_scalar(scale)}x" 

317 needs_parens = True 

318 else: 

319 term = ( 

320 f"{self._repr_latex_scalar(off)} + " 

321 f"{self._repr_latex_scalar(scale)}x" 

322 ) 

323 needs_parens = True 

324 

325 mute = r"\color{{LightGray}}{{{}}}".format 

326 

327 parts = [] 

328 for i, c in enumerate(self.coef): 

329 # prevent duplication of + and - signs 

330 if i == 0: 

331 coef_str = f"{self._repr_latex_scalar(c)}" 

332 elif not isinstance(c, numbers.Real): 

333 coef_str = f" + ({self._repr_latex_scalar(c)})" 

334 elif not np.signbit(c): 

335 coef_str = f" + {self._repr_latex_scalar(c)}" 

336 else: 

337 coef_str = f" - {self._repr_latex_scalar(-c)}" 

338 

339 # produce the string for the term 

340 term_str = self._repr_latex_term(i, term, needs_parens) 

341 if term_str == '1': 

342 part = coef_str 

343 else: 

344 part = rf"{coef_str}\,{term_str}" 

345 

346 if c == 0: 

347 part = mute(part) 

348 

349 parts.append(part) 

350 

351 if parts: 

352 body = ''.join(parts) 

353 else: 

354 # in case somehow there are no coefficients at all 

355 body = '0' 

356 

357 return rf"$x \mapsto {body}$" 

358 

359 

360 

361 # Pickle and copy 

362 

363 def __getstate__(self): 

364 ret = self.__dict__.copy() 

365 ret['coef'] = self.coef.copy() 

366 ret['domain'] = self.domain.copy() 

367 ret['window'] = self.window.copy() 

368 return ret 

369 

370 def __setstate__(self, dict): 

371 self.__dict__ = dict 

372 

373 # Call 

374 

375 def __call__(self, arg): 

376 off, scl = pu.mapparms(self.domain, self.window) 

377 arg = off + scl*arg 

378 return self._val(arg, self.coef) 

379 

380 def __iter__(self): 

381 return iter(self.coef) 

382 

383 def __len__(self): 

384 return len(self.coef) 

385 

386 # Numeric properties. 

387 

388 def __neg__(self): 

389 return self.__class__(-self.coef, self.domain, self.window) 

390 

391 def __pos__(self): 

392 return self 

393 

394 def __add__(self, other): 

395 othercoef = self._get_coefficients(other) 

396 try: 

397 coef = self._add(self.coef, othercoef) 

398 except Exception: 

399 return NotImplemented 

400 return self.__class__(coef, self.domain, self.window) 

401 

402 def __sub__(self, other): 

403 othercoef = self._get_coefficients(other) 

404 try: 

405 coef = self._sub(self.coef, othercoef) 

406 except Exception: 

407 return NotImplemented 

408 return self.__class__(coef, self.domain, self.window) 

409 

410 def __mul__(self, other): 

411 othercoef = self._get_coefficients(other) 

412 try: 

413 coef = self._mul(self.coef, othercoef) 

414 except Exception: 

415 return NotImplemented 

416 return self.__class__(coef, self.domain, self.window) 

417 

418 def __truediv__(self, other): 

419 # there is no true divide if the rhs is not a Number, although it 

420 # could return the first n elements of an infinite series. 

421 # It is hard to see where n would come from, though. 

422 if not isinstance(other, numbers.Number) or isinstance(other, bool): 

423 raise TypeError( 

424 f"unsupported types for true division: " 

425 f"'{type(self)}', '{type(other)}'" 

426 ) 

427 return self.__floordiv__(other) 

428 

429 def __floordiv__(self, other): 

430 res = self.__divmod__(other) 

431 if res is NotImplemented: 

432 return res 

433 return res[0] 

434 

435 def __mod__(self, other): 

436 res = self.__divmod__(other) 

437 if res is NotImplemented: 

438 return res 

439 return res[1] 

440 

441 def __divmod__(self, other): 

442 othercoef = self._get_coefficients(other) 

443 try: 

444 quo, rem = self._div(self.coef, othercoef) 

445 except ZeroDivisionError as e: 

446 raise e 

447 except Exception: 

448 return NotImplemented 

449 quo = self.__class__(quo, self.domain, self.window) 

450 rem = self.__class__(rem, self.domain, self.window) 

451 return quo, rem 

452 

453 def __pow__(self, other): 

454 coef = self._pow(self.coef, other, maxpower=self.maxpower) 

455 res = self.__class__(coef, self.domain, self.window) 

456 return res 

457 

458 def __radd__(self, other): 

459 try: 

460 coef = self._add(other, self.coef) 

461 except Exception: 

462 return NotImplemented 

463 return self.__class__(coef, self.domain, self.window) 

464 

465 def __rsub__(self, other): 

466 try: 

467 coef = self._sub(other, self.coef) 

468 except Exception: 

469 return NotImplemented 

470 return self.__class__(coef, self.domain, self.window) 

471 

472 def __rmul__(self, other): 

473 try: 

474 coef = self._mul(other, self.coef) 

475 except Exception: 

476 return NotImplemented 

477 return self.__class__(coef, self.domain, self.window) 

478 

479 def __rdiv__(self, other): 

480 # set to __floordiv__ /. 

481 return self.__rfloordiv__(other) 

482 

483 def __rtruediv__(self, other): 

484 # An instance of ABCPolyBase is not considered a 

485 # Number. 

486 return NotImplemented 

487 

488 def __rfloordiv__(self, other): 

489 res = self.__rdivmod__(other) 

490 if res is NotImplemented: 

491 return res 

492 return res[0] 

493 

494 def __rmod__(self, other): 

495 res = self.__rdivmod__(other) 

496 if res is NotImplemented: 

497 return res 

498 return res[1] 

499 

500 def __rdivmod__(self, other): 

501 try: 

502 quo, rem = self._div(other, self.coef) 

503 except ZeroDivisionError as e: 

504 raise e 

505 except Exception: 

506 return NotImplemented 

507 quo = self.__class__(quo, self.domain, self.window) 

508 rem = self.__class__(rem, self.domain, self.window) 

509 return quo, rem 

510 

511 def __eq__(self, other): 

512 res = (isinstance(other, self.__class__) and 

513 np.all(self.domain == other.domain) and 

514 np.all(self.window == other.window) and 

515 (self.coef.shape == other.coef.shape) and 

516 np.all(self.coef == other.coef)) 

517 return res 

518 

519 def __ne__(self, other): 

520 return not self.__eq__(other) 

521 

522 # 

523 # Extra methods. 

524 # 

525 

526 def copy(self): 

527 """Return a copy. 

528 

529 Returns 

530 ------- 

531 new_series : series 

532 Copy of self. 

533 

534 """ 

535 return self.__class__(self.coef, self.domain, self.window) 

536 

537 def degree(self): 

538 """The degree of the series. 

539 

540 .. versionadded:: 1.5.0 

541 

542 Returns 

543 ------- 

544 degree : int 

545 Degree of the series, one less than the number of coefficients. 

546 

547 """ 

548 return len(self) - 1 

549 

550 def cutdeg(self, deg): 

551 """Truncate series to the given degree. 

552 

553 Reduce the degree of the series to `deg` by discarding the 

554 high order terms. If `deg` is greater than the current degree a 

555 copy of the current series is returned. This can be useful in least 

556 squares where the coefficients of the high degree terms may be very 

557 small. 

558 

559 .. versionadded:: 1.5.0 

560 

561 Parameters 

562 ---------- 

563 deg : non-negative int 

564 The series is reduced to degree `deg` by discarding the high 

565 order terms. The value of `deg` must be a non-negative integer. 

566 

567 Returns 

568 ------- 

569 new_series : series 

570 New instance of series with reduced degree. 

571 

572 """ 

573 return self.truncate(deg + 1) 

574 

575 def trim(self, tol=0): 

576 """Remove trailing coefficients 

577 

578 Remove trailing coefficients until a coefficient is reached whose 

579 absolute value greater than `tol` or the beginning of the series is 

580 reached. If all the coefficients would be removed the series is set 

581 to ``[0]``. A new series instance is returned with the new 

582 coefficients. The current instance remains unchanged. 

583 

584 Parameters 

585 ---------- 

586 tol : non-negative number. 

587 All trailing coefficients less than `tol` will be removed. 

588 

589 Returns 

590 ------- 

591 new_series : series 

592 Contains the new set of coefficients. 

593 

594 """ 

595 coef = pu.trimcoef(self.coef, tol) 

596 return self.__class__(coef, self.domain, self.window) 

597 

598 def truncate(self, size): 

599 """Truncate series to length `size`. 

600 

601 Reduce the series to length `size` by discarding the high 

602 degree terms. The value of `size` must be a positive integer. This 

603 can be useful in least squares where the coefficients of the 

604 high degree terms may be very small. 

605 

606 Parameters 

607 ---------- 

608 size : positive int 

609 The series is reduced to length `size` by discarding the high 

610 degree terms. The value of `size` must be a positive integer. 

611 

612 Returns 

613 ------- 

614 new_series : series 

615 New instance of series with truncated coefficients. 

616 

617 """ 

618 isize = int(size) 

619 if isize != size or isize < 1: 

620 raise ValueError("size must be a positive integer") 

621 if isize >= len(self.coef): 

622 coef = self.coef 

623 else: 

624 coef = self.coef[:isize] 

625 return self.__class__(coef, self.domain, self.window) 

626 

627 def convert(self, domain=None, kind=None, window=None): 

628 """Convert series to a different kind and/or domain and/or window. 

629 

630 Parameters 

631 ---------- 

632 domain : array_like, optional 

633 The domain of the converted series. If the value is None, 

634 the default domain of `kind` is used. 

635 kind : class, optional 

636 The polynomial series type class to which the current instance 

637 should be converted. If kind is None, then the class of the 

638 current instance is used. 

639 window : array_like, optional 

640 The window of the converted series. If the value is None, 

641 the default window of `kind` is used. 

642 

643 Returns 

644 ------- 

645 new_series : series 

646 The returned class can be of different type than the current 

647 instance and/or have a different domain and/or different 

648 window. 

649 

650 Notes 

651 ----- 

652 Conversion between domains and class types can result in 

653 numerically ill defined series. 

654 

655 Examples 

656 -------- 

657 

658 """ 

659 if kind is None: 

660 kind = self.__class__ 

661 if domain is None: 

662 domain = kind.domain 

663 if window is None: 

664 window = kind.window 

665 return self(kind.identity(domain, window=window)) 

666 

667 def mapparms(self): 

668 """Return the mapping parameters. 

669 

670 The returned values define a linear map ``off + scl*x`` that is 

671 applied to the input arguments before the series is evaluated. The 

672 map depends on the ``domain`` and ``window``; if the current 

673 ``domain`` is equal to the ``window`` the resulting map is the 

674 identity. If the coefficients of the series instance are to be 

675 used by themselves outside this class, then the linear function 

676 must be substituted for the ``x`` in the standard representation of 

677 the base polynomials. 

678 

679 Returns 

680 ------- 

681 off, scl : float or complex 

682 The mapping function is defined by ``off + scl*x``. 

683 

684 Notes 

685 ----- 

686 If the current domain is the interval ``[l1, r1]`` and the window 

687 is ``[l2, r2]``, then the linear mapping function ``L`` is 

688 defined by the equations:: 

689 

690 L(l1) = l2 

691 L(r1) = r2 

692 

693 """ 

694 return pu.mapparms(self.domain, self.window) 

695 

696 def integ(self, m=1, k=[], lbnd=None): 

697 """Integrate. 

698 

699 Return a series instance that is the definite integral of the 

700 current series. 

701 

702 Parameters 

703 ---------- 

704 m : non-negative int 

705 The number of integrations to perform. 

706 k : array_like 

707 Integration constants. The first constant is applied to the 

708 first integration, the second to the second, and so on. The 

709 list of values must less than or equal to `m` in length and any 

710 missing values are set to zero. 

711 lbnd : Scalar 

712 The lower bound of the definite integral. 

713 

714 Returns 

715 ------- 

716 new_series : series 

717 A new series representing the integral. The domain is the same 

718 as the domain of the integrated series. 

719 

720 """ 

721 off, scl = self.mapparms() 

722 if lbnd is None: 

723 lbnd = 0 

724 else: 

725 lbnd = off + scl*lbnd 

726 coef = self._int(self.coef, m, k, lbnd, 1./scl) 

727 return self.__class__(coef, self.domain, self.window) 

728 

729 def deriv(self, m=1): 

730 """Differentiate. 

731 

732 Return a series instance of that is the derivative of the current 

733 series. 

734 

735 Parameters 

736 ---------- 

737 m : non-negative int 

738 Find the derivative of order `m`. 

739 

740 Returns 

741 ------- 

742 new_series : series 

743 A new series representing the derivative. The domain is the same 

744 as the domain of the differentiated series. 

745 

746 """ 

747 off, scl = self.mapparms() 

748 coef = self._der(self.coef, m, scl) 

749 return self.__class__(coef, self.domain, self.window) 

750 

751 def roots(self): 

752 """Return the roots of the series polynomial. 

753 

754 Compute the roots for the series. Note that the accuracy of the 

755 roots decrease the further outside the domain they lie. 

756 

757 Returns 

758 ------- 

759 roots : ndarray 

760 Array containing the roots of the series. 

761 

762 """ 

763 roots = self._roots(self.coef) 

764 return pu.mapdomain(roots, self.window, self.domain) 

765 

766 def linspace(self, n=100, domain=None): 

767 """Return x, y values at equally spaced points in domain. 

768 

769 Returns the x, y values at `n` linearly spaced points across the 

770 domain. Here y is the value of the polynomial at the points x. By 

771 default the domain is the same as that of the series instance. 

772 This method is intended mostly as a plotting aid. 

773 

774 .. versionadded:: 1.5.0 

775 

776 Parameters 

777 ---------- 

778 n : int, optional 

779 Number of point pairs to return. The default value is 100. 

780 domain : {None, array_like}, optional 

781 If not None, the specified domain is used instead of that of 

782 the calling instance. It should be of the form ``[beg,end]``. 

783 The default is None which case the class domain is used. 

784 

785 Returns 

786 ------- 

787 x, y : ndarray 

788 x is equal to linspace(self.domain[0], self.domain[1], n) and 

789 y is the series evaluated at element of x. 

790 

791 """ 

792 if domain is None: 

793 domain = self.domain 

794 x = np.linspace(domain[0], domain[1], n) 

795 y = self(x) 

796 return x, y 

797 

798 @classmethod 

799 def fit(cls, x, y, deg, domain=None, rcond=None, full=False, w=None, 

800 window=None): 

801 """Least squares fit to data. 

802 

803 Return a series instance that is the least squares fit to the data 

804 `y` sampled at `x`. The domain of the returned instance can be 

805 specified and this will often result in a superior fit with less 

806 chance of ill conditioning. 

807 

808 Parameters 

809 ---------- 

810 x : array_like, shape (M,) 

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

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

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

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

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

816 deg : int or 1-D array_like 

817 Degree(s) of the fitting polynomials. If `deg` is a single integer 

818 all terms up to and including the `deg`'th term are included in the 

819 fit. For NumPy versions >= 1.11.0 a list of integers specifying the 

820 degrees of the terms to include may be used instead. 

821 domain : {None, [beg, end], []}, optional 

822 Domain to use for the returned series. If ``None``, 

823 then a minimal domain that covers the points `x` is chosen. If 

824 ``[]`` the class domain is used. The default value was the 

825 class domain in NumPy 1.4 and ``None`` in later versions. 

826 The ``[]`` option was added in numpy 1.5.0. 

827 rcond : float, optional 

828 Relative condition number of the fit. Singular values smaller 

829 than this relative to the largest singular value will be 

830 ignored. The default value is len(x)*eps, where eps is the 

831 relative precision of the float type, about 2e-16 in most 

832 cases. 

833 full : bool, optional 

834 Switch determining nature of return value. When it is False 

835 (the default) just the coefficients are returned, when True 

836 diagnostic information from the singular value decomposition is 

837 also returned. 

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

839 Weights. If not None the contribution of each point 

840 ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the 

841 weights are chosen so that the errors of the products 

842 ``w[i]*y[i]`` all have the same variance. The default value is 

843 None. 

844 

845 .. versionadded:: 1.5.0 

846 window : {[beg, end]}, optional 

847 Window to use for the returned series. The default 

848 value is the default class domain 

849 

850 .. versionadded:: 1.6.0 

851 

852 Returns 

853 ------- 

854 new_series : series 

855 A series that represents the least squares fit to the data and 

856 has the domain and window specified in the call. If the 

857 coefficients for the unscaled and unshifted basis polynomials are 

858 of interest, do ``new_series.convert().coef``. 

859 

860 [resid, rank, sv, rcond] : list 

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

862 

863 resid -- sum of squared residuals of the least squares fit 

864 rank -- the numerical rank of the scaled Vandermonde matrix 

865 sv -- singular values of the scaled Vandermonde matrix 

866 rcond -- value of `rcond`. 

867 

868 For more details, see `linalg.lstsq`. 

869 

870 """ 

871 if domain is None: 

872 domain = pu.getdomain(x) 

873 elif type(domain) is list and len(domain) == 0: 

874 domain = cls.domain 

875 

876 if window is None: 

877 window = cls.window 

878 

879 xnew = pu.mapdomain(x, domain, window) 

880 res = cls._fit(xnew, y, deg, w=w, rcond=rcond, full=full) 

881 if full: 

882 [coef, status] = res 

883 return cls(coef, domain=domain, window=window), status 

884 else: 

885 coef = res 

886 return cls(coef, domain=domain, window=window) 

887 

888 @classmethod 

889 def fromroots(cls, roots, domain=[], window=None): 

890 """Return series instance that has the specified roots. 

891 

892 Returns a series representing the product 

893 ``(x - r[0])*(x - r[1])*...*(x - r[n-1])``, where ``r`` is a 

894 list of roots. 

895 

896 Parameters 

897 ---------- 

898 roots : array_like 

899 List of roots. 

900 domain : {[], None, array_like}, optional 

901 Domain for the resulting series. If None the domain is the 

902 interval from the smallest root to the largest. If [] the 

903 domain is the class domain. The default is []. 

904 window : {None, array_like}, optional 

905 Window for the returned series. If None the class window is 

906 used. The default is None. 

907 

908 Returns 

909 ------- 

910 new_series : series 

911 Series with the specified roots. 

912 

913 """ 

914 [roots] = pu.as_series([roots], trim=False) 

915 if domain is None: 

916 domain = pu.getdomain(roots) 

917 elif type(domain) is list and len(domain) == 0: 

918 domain = cls.domain 

919 

920 if window is None: 

921 window = cls.window 

922 

923 deg = len(roots) 

924 off, scl = pu.mapparms(domain, window) 

925 rnew = off + scl*roots 

926 coef = cls._fromroots(rnew) / scl**deg 

927 return cls(coef, domain=domain, window=window) 

928 

929 @classmethod 

930 def identity(cls, domain=None, window=None): 

931 """Identity function. 

932 

933 If ``p`` is the returned series, then ``p(x) == x`` for all 

934 values of x. 

935 

936 Parameters 

937 ---------- 

938 domain : {None, array_like}, optional 

939 If given, the array must be of the form ``[beg, end]``, where 

940 ``beg`` and ``end`` are the endpoints of the domain. If None is 

941 given then the class domain is used. The default is None. 

942 window : {None, array_like}, optional 

943 If given, the resulting array must be if the form 

944 ``[beg, end]``, where ``beg`` and ``end`` are the endpoints of 

945 the window. If None is given then the class window is used. The 

946 default is None. 

947 

948 Returns 

949 ------- 

950 new_series : series 

951 Series of representing the identity. 

952 

953 """ 

954 if domain is None: 

955 domain = cls.domain 

956 if window is None: 

957 window = cls.window 

958 off, scl = pu.mapparms(window, domain) 

959 coef = cls._line(off, scl) 

960 return cls(coef, domain, window) 

961 

962 @classmethod 

963 def basis(cls, deg, domain=None, window=None): 

964 """Series basis polynomial of degree `deg`. 

965 

966 Returns the series representing the basis polynomial of degree `deg`. 

967 

968 .. versionadded:: 1.7.0 

969 

970 Parameters 

971 ---------- 

972 deg : int 

973 Degree of the basis polynomial for the series. Must be >= 0. 

974 domain : {None, array_like}, optional 

975 If given, the array must be of the form ``[beg, end]``, where 

976 ``beg`` and ``end`` are the endpoints of the domain. If None is 

977 given then the class domain is used. The default is None. 

978 window : {None, array_like}, optional 

979 If given, the resulting array must be if the form 

980 ``[beg, end]``, where ``beg`` and ``end`` are the endpoints of 

981 the window. If None is given then the class window is used. The 

982 default is None. 

983 

984 Returns 

985 ------- 

986 new_series : series 

987 A series with the coefficient of the `deg` term set to one and 

988 all others zero. 

989 

990 """ 

991 if domain is None: 

992 domain = cls.domain 

993 if window is None: 

994 window = cls.window 

995 ideg = int(deg) 

996 

997 if ideg != deg or ideg < 0: 

998 raise ValueError("deg must be non-negative integer") 

999 return cls([0]*ideg + [1], domain, window) 

1000 

1001 @classmethod 

1002 def cast(cls, series, domain=None, window=None): 

1003 """Convert series to series of this class. 

1004 

1005 The `series` is expected to be an instance of some polynomial 

1006 series of one of the types supported by by the numpy.polynomial 

1007 module, but could be some other class that supports the convert 

1008 method. 

1009 

1010 .. versionadded:: 1.7.0 

1011 

1012 Parameters 

1013 ---------- 

1014 series : series 

1015 The series instance to be converted. 

1016 domain : {None, array_like}, optional 

1017 If given, the array must be of the form ``[beg, end]``, where 

1018 ``beg`` and ``end`` are the endpoints of the domain. If None is 

1019 given then the class domain is used. The default is None. 

1020 window : {None, array_like}, optional 

1021 If given, the resulting array must be if the form 

1022 ``[beg, end]``, where ``beg`` and ``end`` are the endpoints of 

1023 the window. If None is given then the class window is used. The 

1024 default is None. 

1025 

1026 Returns 

1027 ------- 

1028 new_series : series 

1029 A series of the same kind as the calling class and equal to 

1030 `series` when evaluated. 

1031 

1032 See Also 

1033 -------- 

1034 convert : similar instance method 

1035 

1036 """ 

1037 if domain is None: 

1038 domain = cls.domain 

1039 if window is None: 

1040 window = cls.window 

1041 return series.convert(domain, cls, window)