Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/numpy/polynomial/_polybase.py : 27%

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.
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.
8"""
9import abc
10import numbers
12import numpy as np
13from . import polyutils as pu
15__all__ = ['ABCPolyBase']
17class ABCPolyBase(abc.ABC):
18 """An abstract base class for immutable series classes.
20 ABCPolyBase provides the standard Python numerical methods
21 '+', '-', '*', '//', '%', 'divmod', '**', and '()' along with the
22 methods listed below.
24 .. versionadded:: 1.9.0
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.
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.
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.
59 """
61 # Not hashable
62 __hash__ = None
64 # Opt out of numpy ufuncs and Python ops with ndarray subclasses.
65 __array_ufunc__ = None
67 # Limit runaway size. T_n^m has degree n*m
68 maxpower = 100
70 @property
71 @abc.abstractmethod
72 def domain(self):
73 pass
75 @property
76 @abc.abstractmethod
77 def window(self):
78 pass
80 @property
81 @abc.abstractmethod
82 def nickname(self):
83 pass
85 @property
86 @abc.abstractmethod
87 def basis_name(self):
88 pass
90 @staticmethod
91 @abc.abstractmethod
92 def _add(c1, c2):
93 pass
95 @staticmethod
96 @abc.abstractmethod
97 def _sub(c1, c2):
98 pass
100 @staticmethod
101 @abc.abstractmethod
102 def _mul(c1, c2):
103 pass
105 @staticmethod
106 @abc.abstractmethod
107 def _div(c1, c2):
108 pass
110 @staticmethod
111 @abc.abstractmethod
112 def _pow(c, pow, maxpower=None):
113 pass
115 @staticmethod
116 @abc.abstractmethod
117 def _val(x, c):
118 pass
120 @staticmethod
121 @abc.abstractmethod
122 def _int(c, m, k, lbnd, scl):
123 pass
125 @staticmethod
126 @abc.abstractmethod
127 def _der(c, m, scl):
128 pass
130 @staticmethod
131 @abc.abstractmethod
132 def _fit(x, y, deg, rcond, full):
133 pass
135 @staticmethod
136 @abc.abstractmethod
137 def _line(off, scl):
138 pass
140 @staticmethod
141 @abc.abstractmethod
142 def _roots(c):
143 pass
145 @staticmethod
146 @abc.abstractmethod
147 def _fromroots(r):
148 pass
150 def has_samecoef(self, other):
151 """Check if coefficients match.
153 .. versionadded:: 1.6.0
155 Parameters
156 ----------
157 other : class instance
158 The other class must have the ``coef`` attribute.
160 Returns
161 -------
162 bool : boolean
163 True if the coefficients are the same, False otherwise.
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
173 def has_samedomain(self, other):
174 """Check if domains match.
176 .. versionadded:: 1.6.0
178 Parameters
179 ----------
180 other : class instance
181 The other class must have the ``domain`` attribute.
183 Returns
184 -------
185 bool : boolean
186 True if the domains are the same, False otherwise.
188 """
189 return np.all(self.domain == other.domain)
191 def has_samewindow(self, other):
192 """Check if windows match.
194 .. versionadded:: 1.6.0
196 Parameters
197 ----------
198 other : class instance
199 The other class must have the ``window`` attribute.
201 Returns
202 -------
203 bool : boolean
204 True if the windows are the same, False otherwise.
206 """
207 return np.all(self.window == other.window)
209 def has_sametype(self, other):
210 """Check if types match.
212 .. versionadded:: 1.7.0
214 Parameters
215 ----------
216 other : object
217 Class instance.
219 Returns
220 -------
221 bool : boolean
222 True if other is same class as self
224 """
225 return isinstance(other, self.__class__)
227 def _get_coefficients(self, other):
228 """Interpret other as polynomial coefficients.
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`.
234 .. versionadded:: 1.9.0
236 Parameters
237 ----------
238 other : anything
239 Object to be checked.
241 Returns
242 -------
243 coef
244 The coefficients of`other` if it is a compatible instance,
245 of ABCPolyBase, otherwise `other`.
247 Raises
248 ------
249 TypeError
250 When `other` is an incompatible instance of ABCPolyBase.
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
263 def __init__(self, coef, domain=None, window=None):
264 [coef] = pu.as_series([coef], trim=False)
265 self.coef = coef
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
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
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})"
286 def __str__(self):
287 coef = str(self.coef)
288 name = self.nickname
289 return f"{name}({coef})"
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})"
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)
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
325 mute = r"\color{{LightGray}}{{{}}}".format
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)}"
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}"
346 if c == 0:
347 part = mute(part)
349 parts.append(part)
351 if parts:
352 body = ''.join(parts)
353 else:
354 # in case somehow there are no coefficients at all
355 body = '0'
357 return rf"$x \mapsto {body}$"
361 # Pickle and copy
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
370 def __setstate__(self, dict):
371 self.__dict__ = dict
373 # Call
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)
380 def __iter__(self):
381 return iter(self.coef)
383 def __len__(self):
384 return len(self.coef)
386 # Numeric properties.
388 def __neg__(self):
389 return self.__class__(-self.coef, self.domain, self.window)
391 def __pos__(self):
392 return self
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)
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)
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)
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)
429 def __floordiv__(self, other):
430 res = self.__divmod__(other)
431 if res is NotImplemented:
432 return res
433 return res[0]
435 def __mod__(self, other):
436 res = self.__divmod__(other)
437 if res is NotImplemented:
438 return res
439 return res[1]
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
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
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)
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)
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)
479 def __rdiv__(self, other):
480 # set to __floordiv__ /.
481 return self.__rfloordiv__(other)
483 def __rtruediv__(self, other):
484 # An instance of ABCPolyBase is not considered a
485 # Number.
486 return NotImplemented
488 def __rfloordiv__(self, other):
489 res = self.__rdivmod__(other)
490 if res is NotImplemented:
491 return res
492 return res[0]
494 def __rmod__(self, other):
495 res = self.__rdivmod__(other)
496 if res is NotImplemented:
497 return res
498 return res[1]
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
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
519 def __ne__(self, other):
520 return not self.__eq__(other)
522 #
523 # Extra methods.
524 #
526 def copy(self):
527 """Return a copy.
529 Returns
530 -------
531 new_series : series
532 Copy of self.
534 """
535 return self.__class__(self.coef, self.domain, self.window)
537 def degree(self):
538 """The degree of the series.
540 .. versionadded:: 1.5.0
542 Returns
543 -------
544 degree : int
545 Degree of the series, one less than the number of coefficients.
547 """
548 return len(self) - 1
550 def cutdeg(self, deg):
551 """Truncate series to the given degree.
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.
559 .. versionadded:: 1.5.0
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.
567 Returns
568 -------
569 new_series : series
570 New instance of series with reduced degree.
572 """
573 return self.truncate(deg + 1)
575 def trim(self, tol=0):
576 """Remove trailing coefficients
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.
584 Parameters
585 ----------
586 tol : non-negative number.
587 All trailing coefficients less than `tol` will be removed.
589 Returns
590 -------
591 new_series : series
592 Contains the new set of coefficients.
594 """
595 coef = pu.trimcoef(self.coef, tol)
596 return self.__class__(coef, self.domain, self.window)
598 def truncate(self, size):
599 """Truncate series to length `size`.
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.
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.
612 Returns
613 -------
614 new_series : series
615 New instance of series with truncated coefficients.
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)
627 def convert(self, domain=None, kind=None, window=None):
628 """Convert series to a different kind and/or domain and/or window.
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.
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.
650 Notes
651 -----
652 Conversion between domains and class types can result in
653 numerically ill defined series.
655 Examples
656 --------
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))
667 def mapparms(self):
668 """Return the mapping parameters.
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.
679 Returns
680 -------
681 off, scl : float or complex
682 The mapping function is defined by ``off + scl*x``.
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::
690 L(l1) = l2
691 L(r1) = r2
693 """
694 return pu.mapparms(self.domain, self.window)
696 def integ(self, m=1, k=[], lbnd=None):
697 """Integrate.
699 Return a series instance that is the definite integral of the
700 current series.
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.
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.
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)
729 def deriv(self, m=1):
730 """Differentiate.
732 Return a series instance of that is the derivative of the current
733 series.
735 Parameters
736 ----------
737 m : non-negative int
738 Find the derivative of order `m`.
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.
746 """
747 off, scl = self.mapparms()
748 coef = self._der(self.coef, m, scl)
749 return self.__class__(coef, self.domain, self.window)
751 def roots(self):
752 """Return the roots of the series polynomial.
754 Compute the roots for the series. Note that the accuracy of the
755 roots decrease the further outside the domain they lie.
757 Returns
758 -------
759 roots : ndarray
760 Array containing the roots of the series.
762 """
763 roots = self._roots(self.coef)
764 return pu.mapdomain(roots, self.window, self.domain)
766 def linspace(self, n=100, domain=None):
767 """Return x, y values at equally spaced points in domain.
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.
774 .. versionadded:: 1.5.0
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.
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.
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
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.
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.
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.
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
850 .. versionadded:: 1.6.0
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``.
860 [resid, rank, sv, rcond] : list
861 These values are only returned if `full` = True
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`.
868 For more details, see `linalg.lstsq`.
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
876 if window is None:
877 window = cls.window
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)
888 @classmethod
889 def fromroots(cls, roots, domain=[], window=None):
890 """Return series instance that has the specified roots.
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.
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.
908 Returns
909 -------
910 new_series : series
911 Series with the specified roots.
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
920 if window is None:
921 window = cls.window
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)
929 @classmethod
930 def identity(cls, domain=None, window=None):
931 """Identity function.
933 If ``p`` is the returned series, then ``p(x) == x`` for all
934 values of x.
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.
948 Returns
949 -------
950 new_series : series
951 Series of representing the identity.
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)
962 @classmethod
963 def basis(cls, deg, domain=None, window=None):
964 """Series basis polynomial of degree `deg`.
966 Returns the series representing the basis polynomial of degree `deg`.
968 .. versionadded:: 1.7.0
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.
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.
990 """
991 if domain is None:
992 domain = cls.domain
993 if window is None:
994 window = cls.window
995 ideg = int(deg)
997 if ideg != deg or ideg < 0:
998 raise ValueError("deg must be non-negative integer")
999 return cls([0]*ideg + [1], domain, window)
1001 @classmethod
1002 def cast(cls, series, domain=None, window=None):
1003 """Convert series to series of this class.
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.
1010 .. versionadded:: 1.7.0
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.
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.
1032 See Also
1033 --------
1034 convert : similar instance method
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)