Chris@87: """ Chris@87: Template for the Chebyshev and Polynomial classes. Chris@87: Chris@87: This module houses a Python string module Template object (see, e.g., Chris@87: http://docs.python.org/library/string.html#template-strings) used by Chris@87: the `polynomial` and `chebyshev` modules to implement their respective Chris@87: `Polynomial` and `Chebyshev` classes. It provides a mechanism for easily Chris@87: creating additional specific polynomial classes (e.g., Legendre, Jacobi, Chris@87: etc.) in the future, such that all these classes will have a common API. Chris@87: Chris@87: """ Chris@87: from __future__ import division, absolute_import, print_function Chris@87: Chris@87: import string Chris@87: import sys Chris@87: import warnings Chris@87: from number import Number Chris@87: Chris@87: from numpy import ModuleDeprecationWarning Chris@87: Chris@87: warnings.warn("The polytemplate module will be removed in Numpy 1.10.0.", Chris@87: ModuleDeprecationWarning) Chris@87: Chris@87: polytemplate = string.Template(''' Chris@87: from __future__ import division, absolute_import, print_function Chris@87: import numpy as np Chris@87: import warnings Chris@87: from . import polyutils as pu Chris@87: Chris@87: class $name(pu.PolyBase) : Chris@87: """A $name series class. Chris@87: Chris@87: $name instances provide the standard Python numerical methods '+', Chris@87: '-', '*', '//', '%', 'divmod', '**', and '()' as well as the listed Chris@87: methods. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: coef : array_like Chris@87: $name coefficients, in increasing order. For example, Chris@87: ``(1, 2, 3)`` implies ``P_0 + 2P_1 + 3P_2`` where the Chris@87: ``P_i`` are a graded polynomial basis. Chris@87: domain : (2,) array_like, optional Chris@87: Domain to use. The interval ``[domain[0], domain[1]]`` is mapped to Chris@87: the interval ``[window[0], window[1]]`` by shifting and scaling. Chris@87: The default value is $domain. Chris@87: window : (2,) array_like, optional Chris@87: Window, see ``domain`` for its use. The default value is $domain. Chris@87: .. versionadded:: 1.6.0 Chris@87: Chris@87: Attributes Chris@87: ---------- Chris@87: coef : (N,) ndarray Chris@87: $name coefficients, from low to high. Chris@87: domain : (2,) ndarray Chris@87: Domain that is mapped to ``window``. Chris@87: window : (2,) ndarray Chris@87: Window that ``domain`` is mapped to. Chris@87: Chris@87: Class Attributes Chris@87: ---------------- Chris@87: maxpower : int Chris@87: Maximum power allowed, i.e., the largest number ``n`` such that Chris@87: ``p(x)**n`` is allowed. This is to limit runaway polynomial size. Chris@87: domain : (2,) ndarray Chris@87: Default domain of the class. Chris@87: window : (2,) ndarray Chris@87: Default window of the class. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: It is important to specify the domain in many cases, for instance in Chris@87: fitting data, because many of the important properties of the Chris@87: polynomial basis only hold in a specified interval and consequently Chris@87: the data must be mapped into that interval in order to benefit. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: Chris@87: """ Chris@87: # Limit runaway size. T_n^m has degree n*2^m Chris@87: maxpower = 16 Chris@87: # Default domain Chris@87: domain = np.array($domain) Chris@87: # Default window Chris@87: window = np.array($domain) Chris@87: # Don't let participate in array operations. Value doesn't matter. Chris@87: __array_priority__ = 1000 Chris@87: # Not hashable Chris@87: __hash__ = None Chris@87: Chris@87: def has_samecoef(self, other): Chris@87: """Check if coefficients match. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: other : class instance Chris@87: The other class must have the ``coef`` attribute. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: bool : boolean Chris@87: True if the coefficients are the same, False otherwise. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: .. versionadded:: 1.6.0 Chris@87: Chris@87: """ Chris@87: if len(self.coef) != len(other.coef): Chris@87: return False Chris@87: elif not np.all(self.coef == other.coef): Chris@87: return False Chris@87: else: Chris@87: return True Chris@87: Chris@87: def has_samedomain(self, other): Chris@87: """Check if domains match. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: other : class instance Chris@87: The other class must have the ``domain`` attribute. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: bool : boolean Chris@87: True if the domains are the same, False otherwise. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: .. versionadded:: 1.6.0 Chris@87: Chris@87: """ Chris@87: return np.all(self.domain == other.domain) Chris@87: Chris@87: def has_samewindow(self, other): Chris@87: """Check if windows match. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: other : class instance Chris@87: The other class must have the ``window`` attribute. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: bool : boolean Chris@87: True if the windows are the same, False otherwise. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: .. versionadded:: 1.6.0 Chris@87: Chris@87: """ Chris@87: return np.all(self.window == other.window) Chris@87: Chris@87: def has_sametype(self, other): Chris@87: """Check if types match. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: other : object Chris@87: Class instance. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: bool : boolean Chris@87: True if other is same class as self Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: .. versionadded:: 1.7.0 Chris@87: Chris@87: """ Chris@87: return isinstance(other, self.__class__) Chris@87: Chris@87: def __init__(self, coef, domain=$domain, window=$domain) : Chris@87: [coef, dom, win] = pu.as_series([coef, domain, window], trim=False) Chris@87: if len(dom) != 2 : Chris@87: raise ValueError("Domain has wrong number of elements.") Chris@87: if len(win) != 2 : Chris@87: raise ValueError("Window has wrong number of elements.") Chris@87: self.coef = coef Chris@87: self.domain = dom Chris@87: self.window = win Chris@87: Chris@87: def __repr__(self): Chris@87: format = "%s(%s, %s, %s)" Chris@87: coef = repr(self.coef)[6:-1] Chris@87: domain = repr(self.domain)[6:-1] Chris@87: window = repr(self.window)[6:-1] Chris@87: return format % ('$name', coef, domain, window) Chris@87: Chris@87: def __str__(self) : Chris@87: format = "%s(%s)" Chris@87: coef = str(self.coef) Chris@87: return format % ('$nick', coef) Chris@87: Chris@87: # Pickle and copy Chris@87: Chris@87: def __getstate__(self) : Chris@87: ret = self.__dict__.copy() Chris@87: ret['coef'] = self.coef.copy() Chris@87: ret['domain'] = self.domain.copy() Chris@87: ret['window'] = self.window.copy() Chris@87: return ret Chris@87: Chris@87: def __setstate__(self, dict) : Chris@87: self.__dict__ = dict Chris@87: Chris@87: # Call Chris@87: Chris@87: def __call__(self, arg) : Chris@87: off, scl = pu.mapparms(self.domain, self.window) Chris@87: arg = off + scl*arg Chris@87: return ${nick}val(arg, self.coef) Chris@87: Chris@87: def __iter__(self) : Chris@87: return iter(self.coef) Chris@87: Chris@87: def __len__(self) : Chris@87: return len(self.coef) Chris@87: Chris@87: # Numeric properties. Chris@87: Chris@87: def __neg__(self) : Chris@87: return self.__class__(-self.coef, self.domain, self.window) Chris@87: Chris@87: def __pos__(self) : Chris@87: return self Chris@87: Chris@87: def __add__(self, other) : Chris@87: """Returns sum""" Chris@87: if isinstance(other, pu.PolyBase): Chris@87: if not self.has_sametype(other): Chris@87: raise TypeError("Polynomial types differ") Chris@87: elif not self.has_samedomain(other): Chris@87: raise TypeError("Domains differ") Chris@87: elif not self.has_samewindow(other): Chris@87: raise TypeError("Windows differ") Chris@87: else: Chris@87: coef = ${nick}add(self.coef, other.coef) Chris@87: else : Chris@87: try : Chris@87: coef = ${nick}add(self.coef, other) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def __sub__(self, other) : Chris@87: """Returns difference""" Chris@87: if isinstance(other, pu.PolyBase): Chris@87: if not self.has_sametype(other): Chris@87: raise TypeError("Polynomial types differ") Chris@87: elif not self.has_samedomain(other): Chris@87: raise TypeError("Domains differ") Chris@87: elif not self.has_samewindow(other): Chris@87: raise TypeError("Windows differ") Chris@87: else: Chris@87: coef = ${nick}sub(self.coef, other.coef) Chris@87: else : Chris@87: try : Chris@87: coef = ${nick}sub(self.coef, other) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def __mul__(self, other) : Chris@87: """Returns product""" Chris@87: if isinstance(other, pu.PolyBase): Chris@87: if not self.has_sametype(other): Chris@87: raise TypeError("Polynomial types differ") Chris@87: elif not self.has_samedomain(other): Chris@87: raise TypeError("Domains differ") Chris@87: elif not self.has_samewindow(other): Chris@87: raise TypeError("Windows differ") Chris@87: else: Chris@87: coef = ${nick}mul(self.coef, other.coef) Chris@87: else : Chris@87: try : Chris@87: coef = ${nick}mul(self.coef, other) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def __div__(self, other): Chris@87: # set to __floordiv__, /, for now. Chris@87: return self.__floordiv__(other) Chris@87: Chris@87: def __truediv__(self, other) : Chris@87: # there is no true divide if the rhs is not a Number, although it Chris@87: # could return the first n elements of an infinite series. Chris@87: # It is hard to see where n would come from, though. Chris@87: if not isinstance(other, Number) or isinstance(other, bool): Chris@87: form = "unsupported types for true division: '%s', '%s'" Chris@87: raise TypeError(form % (type(self), type(other))) Chris@87: return self.__floordiv__(other) Chris@87: Chris@87: def __floordiv__(self, other) : Chris@87: """Returns the quotient.""" Chris@87: if isinstance(other, pu.PolyBase): Chris@87: if not self.has_sametype(other): Chris@87: raise TypeError("Polynomial types differ") Chris@87: elif not self.has_samedomain(other): Chris@87: raise TypeError("Domains differ") Chris@87: elif not self.has_samewindow(other): Chris@87: raise TypeError("Windows differ") Chris@87: else: Chris@87: quo, rem = ${nick}div(self.coef, other.coef) Chris@87: else : Chris@87: try : Chris@87: quo, rem = ${nick}div(self.coef, other) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(quo, self.domain, self.window) Chris@87: Chris@87: def __mod__(self, other) : Chris@87: """Returns the remainder.""" Chris@87: if isinstance(other, pu.PolyBase): Chris@87: if not self.has_sametype(other): Chris@87: raise TypeError("Polynomial types differ") Chris@87: elif not self.has_samedomain(other): Chris@87: raise TypeError("Domains differ") Chris@87: elif not self.has_samewindow(other): Chris@87: raise TypeError("Windows differ") Chris@87: else: Chris@87: quo, rem = ${nick}div(self.coef, other.coef) Chris@87: else : Chris@87: try : Chris@87: quo, rem = ${nick}div(self.coef, other) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(rem, self.domain, self.window) Chris@87: Chris@87: def __divmod__(self, other) : Chris@87: """Returns quo, remainder""" Chris@87: if isinstance(other, self.__class__) : Chris@87: if not self.has_samedomain(other): Chris@87: raise TypeError("Domains are not equal") Chris@87: elif not self.has_samewindow(other): Chris@87: raise TypeError("Windows are not equal") Chris@87: else: Chris@87: quo, rem = ${nick}div(self.coef, other.coef) Chris@87: else : Chris@87: try : Chris@87: quo, rem = ${nick}div(self.coef, other) Chris@87: except : Chris@87: return NotImplemented Chris@87: quo = self.__class__(quo, self.domain, self.window) Chris@87: rem = self.__class__(rem, self.domain, self.window) Chris@87: return quo, rem Chris@87: Chris@87: def __pow__(self, other) : Chris@87: try : Chris@87: coef = ${nick}pow(self.coef, other, maxpower = self.maxpower) Chris@87: except : Chris@87: raise Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def __radd__(self, other) : Chris@87: try : Chris@87: coef = ${nick}add(other, self.coef) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def __rsub__(self, other): Chris@87: try : Chris@87: coef = ${nick}sub(other, self.coef) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def __rmul__(self, other) : Chris@87: try : Chris@87: coef = ${nick}mul(other, self.coef) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def __rdiv__(self, other): Chris@87: # set to __floordiv__ /. Chris@87: return self.__rfloordiv__(other) Chris@87: Chris@87: def __rtruediv__(self, other) : Chris@87: # An instance of PolyBase is not considered a Chris@87: # Number. Chris@87: return NotImplemented Chris@87: Chris@87: def __rfloordiv__(self, other) : Chris@87: try : Chris@87: quo, rem = ${nick}div(other, self.coef) Chris@87: except: Chris@87: return NotImplemented Chris@87: return self.__class__(quo, self.domain, self.window) Chris@87: Chris@87: def __rmod__(self, other) : Chris@87: try : Chris@87: quo, rem = ${nick}div(other, self.coef) Chris@87: except : Chris@87: return NotImplemented Chris@87: return self.__class__(rem, self.domain, self.window) Chris@87: Chris@87: def __rdivmod__(self, other) : Chris@87: try : Chris@87: quo, rem = ${nick}div(other, self.coef) Chris@87: except : Chris@87: return NotImplemented Chris@87: quo = self.__class__(quo, self.domain, self.window) Chris@87: rem = self.__class__(rem, self.domain, self.window) Chris@87: return quo, rem Chris@87: Chris@87: # Enhance me Chris@87: # some augmented arithmetic operations could be added here Chris@87: Chris@87: def __eq__(self, other) : Chris@87: res = isinstance(other, self.__class__) \ Chris@87: and self.has_samecoef(other) \ Chris@87: and self.has_samedomain(other) \ Chris@87: and self.has_samewindow(other) Chris@87: return res Chris@87: Chris@87: def __ne__(self, other) : Chris@87: return not self.__eq__(other) Chris@87: Chris@87: # Chris@87: # Extra methods. Chris@87: # Chris@87: Chris@87: def copy(self) : Chris@87: """Return a copy. Chris@87: Chris@87: Return a copy of the current $name instance. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: new_instance : $name Chris@87: Copy of current instance. Chris@87: Chris@87: """ Chris@87: return self.__class__(self.coef, self.domain, self.window) Chris@87: Chris@87: def degree(self) : Chris@87: """The degree of the series. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: .. versionadded:: 1.5.0 Chris@87: Chris@87: """ Chris@87: return len(self) - 1 Chris@87: Chris@87: def cutdeg(self, deg) : Chris@87: """Truncate series to the given degree. Chris@87: Chris@87: Reduce the degree of the $name series to `deg` by discarding the Chris@87: high order terms. If `deg` is greater than the current degree a Chris@87: copy of the current series is returned. This can be useful in least Chris@87: squares where the coefficients of the high degree terms may be very Chris@87: small. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: deg : non-negative int Chris@87: The series is reduced to degree `deg` by discarding the high Chris@87: order terms. The value of `deg` must be a non-negative integer. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: new_instance : $name Chris@87: New instance of $name with reduced degree. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: .. versionadded:: 1.5.0 Chris@87: Chris@87: """ Chris@87: return self.truncate(deg + 1) Chris@87: Chris@87: def trim(self, tol=0) : Chris@87: """Remove small leading coefficients Chris@87: Chris@87: Remove leading coefficients until a coefficient is reached whose Chris@87: absolute value greater than `tol` or the beginning of the series is Chris@87: reached. If all the coefficients would be removed the series is set to Chris@87: ``[0]``. A new $name instance is returned with the new coefficients. Chris@87: The current instance remains unchanged. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: tol : non-negative number. Chris@87: All trailing coefficients less than `tol` will be removed. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: new_instance : $name Chris@87: Contains the new set of coefficients. Chris@87: Chris@87: """ Chris@87: coef = pu.trimcoef(self.coef, tol) Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def truncate(self, size) : Chris@87: """Truncate series to length `size`. Chris@87: Chris@87: Reduce the $name series to length `size` by discarding the high Chris@87: degree terms. The value of `size` must be a positive integer. This Chris@87: can be useful in least squares where the coefficients of the Chris@87: high degree terms may be very small. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: size : positive int Chris@87: The series is reduced to length `size` by discarding the high Chris@87: degree terms. The value of `size` must be a positive integer. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: new_instance : $name Chris@87: New instance of $name with truncated coefficients. Chris@87: Chris@87: """ Chris@87: isize = int(size) Chris@87: if isize != size or isize < 1 : Chris@87: raise ValueError("size must be a positive integer") Chris@87: if isize >= len(self.coef) : Chris@87: coef = self.coef Chris@87: else : Chris@87: coef = self.coef[:isize] Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def convert(self, domain=None, kind=None, window=None) : Chris@87: """Convert to different class and/or domain. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: domain : array_like, optional Chris@87: The domain of the converted series. If the value is None, Chris@87: the default domain of `kind` is used. Chris@87: kind : class, optional Chris@87: The polynomial series type class to which the current instance Chris@87: should be converted. If kind is None, then the class of the Chris@87: current instance is used. Chris@87: window : array_like, optional Chris@87: The window of the converted series. If the value is None, Chris@87: the default window of `kind` is used. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: new_series_instance : `kind` Chris@87: The returned class can be of different type than the current Chris@87: instance and/or have a different domain. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: Conversion between domains and class types can result in Chris@87: numerically ill defined series. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: Chris@87: """ Chris@87: if kind is None: Chris@87: kind = $name Chris@87: if domain is None: Chris@87: domain = kind.domain Chris@87: if window is None: Chris@87: window = kind.window Chris@87: return self(kind.identity(domain, window=window)) Chris@87: Chris@87: def mapparms(self) : Chris@87: """Return the mapping parameters. Chris@87: Chris@87: The returned values define a linear map ``off + scl*x`` that is Chris@87: applied to the input arguments before the series is evaluated. The Chris@87: map depends on the ``domain`` and ``window``; if the current Chris@87: ``domain`` is equal to the ``window`` the resulting map is the Chris@87: identity. If the coefficients of the ``$name`` instance are to be Chris@87: used by themselves outside this class, then the linear function Chris@87: must be substituted for the ``x`` in the standard representation of Chris@87: the base polynomials. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: off, scl : floats or complex Chris@87: The mapping function is defined by ``off + scl*x``. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: If the current domain is the interval ``[l_1, r_1]`` and the window Chris@87: is ``[l_2, r_2]``, then the linear mapping function ``L`` is Chris@87: defined by the equations:: Chris@87: Chris@87: L(l_1) = l_2 Chris@87: L(r_1) = r_2 Chris@87: Chris@87: """ Chris@87: return pu.mapparms(self.domain, self.window) Chris@87: Chris@87: def integ(self, m=1, k=[], lbnd=None) : Chris@87: """Integrate. Chris@87: Chris@87: Return an instance of $name that is the definite integral of the Chris@87: current series. Refer to `${nick}int` for full documentation. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: m : non-negative int Chris@87: The number of integrations to perform. Chris@87: k : array_like Chris@87: Integration constants. The first constant is applied to the Chris@87: first integration, the second to the second, and so on. The Chris@87: list of values must less than or equal to `m` in length and any Chris@87: missing values are set to zero. Chris@87: lbnd : Scalar Chris@87: The lower bound of the definite integral. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: integral : $name Chris@87: The integral of the series using the same domain. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: ${nick}int : similar function. Chris@87: ${nick}der : similar function for derivative. Chris@87: Chris@87: """ Chris@87: off, scl = self.mapparms() Chris@87: if lbnd is None : Chris@87: lbnd = 0 Chris@87: else : Chris@87: lbnd = off + scl*lbnd Chris@87: coef = ${nick}int(self.coef, m, k, lbnd, 1./scl) Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def deriv(self, m=1): Chris@87: """Differentiate. Chris@87: Chris@87: Return an instance of $name that is the derivative of the current Chris@87: series. Refer to `${nick}der` for full documentation. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: m : non-negative int Chris@87: The number of integrations to perform. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: derivative : $name Chris@87: The derivative of the series using the same domain. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: ${nick}der : similar function. Chris@87: ${nick}int : similar function for integration. Chris@87: Chris@87: """ Chris@87: off, scl = self.mapparms() Chris@87: coef = ${nick}der(self.coef, m, scl) Chris@87: return self.__class__(coef, self.domain, self.window) Chris@87: Chris@87: def roots(self) : Chris@87: """Return list of roots. Chris@87: Chris@87: Return ndarray of roots for this series. See `${nick}roots` for Chris@87: full documentation. Note that the accuracy of the roots is likely to Chris@87: decrease the further outside the domain they lie. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: ${nick}roots : similar function Chris@87: ${nick}fromroots : function to go generate series from roots. Chris@87: Chris@87: """ Chris@87: roots = ${nick}roots(self.coef) Chris@87: return pu.mapdomain(roots, self.window, self.domain) Chris@87: Chris@87: def linspace(self, n=100, domain=None): Chris@87: """Return x,y values at equally spaced points in domain. Chris@87: Chris@87: Returns x, y values at `n` linearly spaced points across domain. Chris@87: Here y is the value of the polynomial at the points x. By default Chris@87: the domain is the same as that of the $name instance. This method Chris@87: is intended mostly as a plotting aid. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: n : int, optional Chris@87: Number of point pairs to return. The default value is 100. Chris@87: domain : {None, array_like} Chris@87: If not None, the specified domain is used instead of that of Chris@87: the calling instance. It should be of the form ``[beg,end]``. Chris@87: The default is None. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: x, y : ndarrays Chris@87: ``x`` is equal to linspace(self.domain[0], self.domain[1], n) Chris@87: ``y`` is the polynomial evaluated at ``x``. Chris@87: Chris@87: .. versionadded:: 1.5.0 Chris@87: Chris@87: """ Chris@87: if domain is None: Chris@87: domain = self.domain Chris@87: x = np.linspace(domain[0], domain[1], n) Chris@87: y = self(x) Chris@87: return x, y Chris@87: Chris@87: Chris@87: Chris@87: @staticmethod Chris@87: def fit(x, y, deg, domain=None, rcond=None, full=False, w=None, Chris@87: window=$domain): Chris@87: """Least squares fit to data. Chris@87: Chris@87: Return a `$name` instance that is the least squares fit to the data Chris@87: `y` sampled at `x`. Unlike `${nick}fit`, the domain of the returned Chris@87: instance can be specified and this will often result in a superior Chris@87: fit with less chance of ill conditioning. Support for NA was added Chris@87: in version 1.7.0. See `${nick}fit` for full documentation of the Chris@87: implementation. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: x : array_like, shape (M,) Chris@87: x-coordinates of the M sample points ``(x[i], y[i])``. Chris@87: y : array_like, shape (M,) or (M, K) Chris@87: y-coordinates of the sample points. Several data sets of sample Chris@87: points sharing the same x-coordinates can be fitted at once by Chris@87: passing in a 2D-array that contains one dataset per column. Chris@87: deg : int Chris@87: Degree of the fitting polynomial. Chris@87: domain : {None, [beg, end], []}, optional Chris@87: Domain to use for the returned $name instance. If ``None``, Chris@87: then a minimal domain that covers the points `x` is chosen. If Chris@87: ``[]`` the default domain ``$domain`` is used. The default Chris@87: value is $domain in numpy 1.4.x and ``None`` in later versions. Chris@87: The ``[]`` value was added in numpy 1.5.0. Chris@87: rcond : float, optional Chris@87: Relative condition number of the fit. Singular values smaller Chris@87: than this relative to the largest singular value will be Chris@87: ignored. The default value is len(x)*eps, where eps is the Chris@87: relative precision of the float type, about 2e-16 in most Chris@87: cases. Chris@87: full : bool, optional Chris@87: Switch determining nature of return value. When it is False Chris@87: (the default) just the coefficients are returned, when True Chris@87: diagnostic information from the singular value decomposition is Chris@87: also returned. Chris@87: w : array_like, shape (M,), optional Chris@87: Weights. If not None the contribution of each point Chris@87: ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the Chris@87: weights are chosen so that the errors of the products Chris@87: ``w[i]*y[i]`` all have the same variance. The default value is Chris@87: None. Chris@87: .. versionadded:: 1.5.0 Chris@87: window : {[beg, end]}, optional Chris@87: Window to use for the returned $name instance. The default Chris@87: value is ``$domain`` Chris@87: .. versionadded:: 1.6.0 Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: least_squares_fit : instance of $name Chris@87: The $name instance is the least squares fit to the data and Chris@87: has the domain specified in the call. Chris@87: Chris@87: [residuals, rank, singular_values, rcond] : only if `full` = True Chris@87: Residuals of the least squares fit, the effective rank of the Chris@87: scaled Vandermonde matrix and its singular values, and the Chris@87: specified value of `rcond`. For more details, see Chris@87: `linalg.lstsq`. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: ${nick}fit : similar function Chris@87: Chris@87: """ Chris@87: if domain is None: Chris@87: domain = pu.getdomain(x) Chris@87: elif type(domain) is list and len(domain) == 0: Chris@87: domain = $domain Chris@87: Chris@87: if type(window) is list and len(window) == 0: Chris@87: window = $domain Chris@87: Chris@87: xnew = pu.mapdomain(x, domain, window) Chris@87: res = ${nick}fit(xnew, y, deg, w=w, rcond=rcond, full=full) Chris@87: if full : Chris@87: [coef, status] = res Chris@87: return $name(coef, domain=domain, window=window), status Chris@87: else : Chris@87: coef = res Chris@87: return $name(coef, domain=domain, window=window) Chris@87: Chris@87: @staticmethod Chris@87: def fromroots(roots, domain=$domain, window=$domain) : Chris@87: """Return $name instance with specified roots. Chris@87: Chris@87: Returns an instance of $name representing the product Chris@87: ``(x - r[0])*(x - r[1])*...*(x - r[n-1])``, where ``r`` is the Chris@87: list of roots. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: roots : array_like Chris@87: List of roots. Chris@87: domain : {array_like, None}, optional Chris@87: Domain for the resulting instance of $name. If none the domain Chris@87: is the interval from the smallest root to the largest. The Chris@87: default is $domain. Chris@87: window : array_like, optional Chris@87: Window for the resulting instance of $name. The default value Chris@87: is $domain. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: object : $name instance Chris@87: Series with the specified roots. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: ${nick}fromroots : equivalent function Chris@87: Chris@87: """ Chris@87: [roots] = pu.as_series([roots], trim=False) Chris@87: if domain is None : Chris@87: domain = pu.getdomain(roots) Chris@87: deg = len(roots) Chris@87: off, scl = pu.mapparms(domain, window) Chris@87: rnew = off + scl*roots Chris@87: coef = ${nick}fromroots(rnew) / scl**deg Chris@87: return $name(coef, domain=domain, window=window) Chris@87: Chris@87: @staticmethod Chris@87: def identity(domain=$domain, window=$domain) : Chris@87: """Identity function. Chris@87: Chris@87: If ``p`` is the returned $name object, then ``p(x) == x`` for all Chris@87: values of x. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: domain : array_like Chris@87: The resulting array must be of the form ``[beg, end]``, where Chris@87: ``beg`` and ``end`` are the endpoints of the domain. Chris@87: window : array_like Chris@87: The resulting array must be if the form ``[beg, end]``, where Chris@87: ``beg`` and ``end`` are the endpoints of the window. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: identity : $name instance Chris@87: Chris@87: """ Chris@87: off, scl = pu.mapparms(window, domain) Chris@87: coef = ${nick}line(off, scl) Chris@87: return $name(coef, domain, window) Chris@87: Chris@87: @staticmethod Chris@87: def basis(deg, domain=$domain, window=$domain): Chris@87: """$name polynomial of degree `deg`. Chris@87: Chris@87: Returns an instance of the $name polynomial of degree `d`. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: deg : int Chris@87: Degree of the $name polynomial. Must be >= 0. Chris@87: domain : array_like Chris@87: The resulting array must be of the form ``[beg, end]``, where Chris@87: ``beg`` and ``end`` are the endpoints of the domain. Chris@87: window : array_like Chris@87: The resulting array must be if the form ``[beg, end]``, where Chris@87: ``beg`` and ``end`` are the endpoints of the window. Chris@87: Chris@87: Returns Chris@87: p : $name instance Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: .. versionadded:: 1.7.0 Chris@87: Chris@87: """ Chris@87: ideg = int(deg) Chris@87: if ideg != deg or ideg < 0: Chris@87: raise ValueError("deg must be non-negative integer") Chris@87: return $name([0]*ideg + [1], domain, window) Chris@87: Chris@87: @staticmethod Chris@87: def cast(series, domain=$domain, window=$domain): Chris@87: """Convert instance to equivalent $name series. Chris@87: Chris@87: The `series` is expected to be an instance of some polynomial Chris@87: series of one of the types supported by by the numpy.polynomial Chris@87: module, but could be some other class that supports the convert Chris@87: method. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: series : series Chris@87: The instance series to be converted. Chris@87: domain : array_like Chris@87: The resulting array must be of the form ``[beg, end]``, where Chris@87: ``beg`` and ``end`` are the endpoints of the domain. Chris@87: window : array_like Chris@87: The resulting array must be if the form ``[beg, end]``, where Chris@87: ``beg`` and ``end`` are the endpoints of the window. Chris@87: Chris@87: Returns Chris@87: p : $name instance Chris@87: A $name series equal to the `poly` series. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: convert -- similar instance method Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: .. versionadded:: 1.7.0 Chris@87: Chris@87: """ Chris@87: return series.convert(domain, $name, window) Chris@87: Chris@87: ''')