diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2011-03-14 10:22:02 -0600 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2011-03-14 10:22:02 -0600 |
commit | cd97607e2f14ac5489215549cb7ff7123394386f (patch) | |
tree | 94e311b36e16ca676b07540ed87d34b8439e7550 /numpy/polynomial/polytemplate.py | |
parent | 782ba88d601ffe0f2f8373b01279d362d402de8b (diff) | |
parent | c2e4c9c034a3446de643fb4f8e96d21249abb7b9 (diff) | |
download | numpy-cd97607e2f14ac5489215549cb7ff7123394386f.tar.gz |
Merge branch 'poly'
Diffstat (limited to 'numpy/polynomial/polytemplate.py')
-rw-r--r-- | numpy/polynomial/polytemplate.py | 379 |
1 files changed, 250 insertions, 129 deletions
diff --git a/numpy/polynomial/polytemplate.py b/numpy/polynomial/polytemplate.py index 2106ad84e..657b48508 100644 --- a/numpy/polynomial/polytemplate.py +++ b/numpy/polynomial/polytemplate.py @@ -31,16 +31,22 @@ class $name(pu.PolyBase) : $name coefficients, in increasing order. For example, ``(1, 2, 3)`` implies ``P_0 + 2P_1 + 3P_2`` where the ``P_i`` are a graded polynomial basis. - domain : (2,) array_like + domain : (2,) array_like, optional Domain to use. The interval ``[domain[0], domain[1]]`` is mapped to - the interval ``$domain`` by shifting and scaling. + the interval ``[window[0], window[1]]`` by shifting and scaling. + The default value is $domain. + window : (2,) array_like, optional + Window, see ``domain`` for its use. The default value is $domain. + .. versionadded:: 1.6.0 Attributes ---------- coef : (N,) array $name coefficients, from low to high. - domain : (2,) array_like - Domain that is mapped to ``$domain``. + domain : (2,) array + Domain that is mapped to ``window``. + window : (2,) array + Window that ``domain`` is mapped to. Class Attributes ---------------- @@ -49,6 +55,8 @@ class $name(pu.PolyBase) : ``p(x)**n`` is allowed. This is to limit runaway polynomial size. domain : (2,) ndarray Default domain of the class. + window : (2,) ndarray + Default window of the class. Notes ----- @@ -65,25 +73,115 @@ class $name(pu.PolyBase) : maxpower = 16 # Default domain domain = np.array($domain) + # Default window + window = np.array($domain) # Don't let participate in array operations. Value doesn't matter. __array_priority__ = 0 - def __init__(self, coef, domain=$domain) : - [coef, domain] = pu.as_series([coef, domain], trim=False) - if len(domain) != 2 : + def has_samecoef(self, other): + """Check if coefficients match. + + Parameters + ---------- + other : class instance + The other class must have the ``coef`` attribute. + + Returns + ------- + bool : boolean + True if the coefficients are the same, False otherwise. + + Notes + ----- + .. versionadded:: 1.6.0 + + """ + if len(self.coef) != len(other.coef): + return False + elif not np.all(self.coef == other.coef): + return False + else: + return True + + def has_samedomain(self, other): + """Check if domains match. + + Parameters + ---------- + other : class instance + The other class must have the ``domain`` attribute. + + Returns + ------- + bool : boolean + True if the domains are the same, False otherwise. + + Notes + ----- + .. versionadded:: 1.6.0 + + """ + return np.all(self.domain == other.domain) + + def has_samewindow(self, other): + """Check if windows match. + + Parameters + ---------- + other : class instance + The other class must have the ``window`` attribute. + + Returns + ------- + bool : boolean + True if the windows are the same, False otherwise. + + Notes + ----- + .. versionadded:: 1.6.0 + + """ + return np.all(self.window == other.window) + + def has_samewindow(self, other): + """Check if windows match. + + Parameters + ---------- + other : class instance + The other class must have the ``window`` attribute. + + Returns + ------- + bool : boolean + True if the windows are the same, False otherwise. + + """ + return np.all(self.window == other.window) + + def __init__(self, coef, domain=$domain, window=$domain) : + [coef, dom, win] = pu.as_series([coef, domain, window], trim=False) + if len(dom) != 2 : raise ValueError("Domain has wrong number of elements.") + if len(win) != 2 : + raise ValueError("Window has wrong number of elements.") self.coef = coef - self.domain = domain + self.domain = dom + self.window = win def __repr__(self): - format = "%s(%s, %s)" + format = "%s(%s, %s, %s)" coef = repr(self.coef)[6:-1] domain = repr(self.domain)[6:-1] - return format % ('$name', coef, domain) + window = repr(self.domain)[6:-1] + return format % ('$name', coef, domain, window) def __str__(self) : - format = "%s(%s, %s)" - return format % ('$nick', str(self.coef), str(self.domain)) + format = "%s(%s, %s, %s)" + coef = str(self.coef)[6:-1] + domain = str(self.domain)[6:-1] + window = str(self.domain)[6:-1] + return format % ('$nick', coef, domain, window) # Pickle and copy @@ -91,6 +189,7 @@ class $name(pu.PolyBase) : ret = self.__dict__.copy() ret['coef'] = self.coef.copy() ret['domain'] = self.domain.copy() + ret['window'] = self.window.copy() return ret def __setstate__(self, dict) : @@ -99,11 +198,10 @@ class $name(pu.PolyBase) : # Call def __call__(self, arg) : - off, scl = pu.mapparms(self.domain, $domain) + off, scl = pu.mapparms(self.domain, self.window) arg = off + scl*arg return ${nick}val(arg, self.coef) - def __iter__(self) : return iter(self.coef) @@ -112,9 +210,8 @@ class $name(pu.PolyBase) : # Numeric properties. - def __neg__(self) : - return self.__class__(-self.coef, self.domain) + return self.__class__(-self.coef, self.domain, self.window) def __pos__(self) : return self @@ -122,7 +219,7 @@ class $name(pu.PolyBase) : def __add__(self, other) : """Returns sum""" if isinstance(other, self.__class__) : - if np.all(self.domain == other.domain) : + if self.has_samedomain(other) and self.has_samewindow(other): coef = ${nick}add(self.coef, other.coef) else : raise PolyDomainError() @@ -131,12 +228,12 @@ class $name(pu.PolyBase) : coef = ${nick}add(self.coef, other) except : return NotImplemented - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def __sub__(self, other) : """Returns difference""" if isinstance(other, self.__class__) : - if np.all(self.domain == other.domain) : + if self.has_samedomain(other) and self.has_samewindow(other): coef = ${nick}sub(self.coef, other.coef) else : raise PolyDomainError() @@ -145,12 +242,12 @@ class $name(pu.PolyBase) : coef = ${nick}sub(self.coef, other) except : return NotImplemented - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def __mul__(self, other) : """Returns product""" if isinstance(other, self.__class__) : - if np.all(self.domain == other.domain) : + if self.has_samedomain(other) and self.has_samewindow(other): coef = ${nick}mul(self.coef, other.coef) else : raise PolyDomainError() @@ -159,7 +256,7 @@ class $name(pu.PolyBase) : coef = ${nick}mul(self.coef, other) except : return NotImplemented - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def __div__(self, other): # set to __floordiv__ /. @@ -175,10 +272,11 @@ class $name(pu.PolyBase) : else : return NotImplemented elif np.isscalar(other) : + # this might be overly restrictive coef = self.coef/other else : return NotImplemented - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def __floordiv__(self, other) : """Returns the quotient.""" @@ -192,12 +290,12 @@ class $name(pu.PolyBase) : quo, rem = ${nick}div(self.coef, other) except : return NotImplemented - return self.__class__(quo, self.domain) + return self.__class__(quo, self.domain, self.window) def __mod__(self, other) : """Returns the remainder.""" if isinstance(other, self.__class__) : - if np.all(self.domain == other.domain) : + if self.has_samedomain(other) and self.has_samewindow(other): quo, rem = ${nick}div(self.coef, other.coef) else : raise PolyDomainError() @@ -206,12 +304,12 @@ class $name(pu.PolyBase) : quo, rem = ${nick}div(self.coef, other) except : return NotImplemented - return self.__class__(rem, self.domain) + return self.__class__(rem, self.domain, self.window) def __divmod__(self, other) : """Returns quo, remainder""" if isinstance(other, self.__class__) : - if np.all(self.domain == other.domain) : + if self.has_samedomain(other) and self.has_samewindow(other): quo, rem = ${nick}div(self.coef, other.coef) else : raise PolyDomainError() @@ -220,35 +318,37 @@ class $name(pu.PolyBase) : quo, rem = ${nick}div(self.coef, other) except : return NotImplemented - return self.__class__(quo, self.domain), self.__class__(rem, self.domain) + quo = self.__class__(quo, self.domain, self.window) + rem = self.__class__(rem, self.domain, self.window) + return quo, rem def __pow__(self, other) : try : coef = ${nick}pow(self.coef, other, maxpower = self.maxpower) except : raise - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def __radd__(self, other) : try : coef = ${nick}add(other, self.coef) except : return NotImplemented - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def __rsub__(self, other): try : coef = ${nick}sub(other, self.coef) except : return NotImplemented - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def __rmul__(self, other) : try : coef = ${nick}mul(other, self.coef) except : return NotImplemented - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def __rdiv__(self, other): # set to __floordiv__ /. @@ -263,46 +363,62 @@ class $name(pu.PolyBase) : quo, rem = ${nick}div(other, self.coef[0]) except : return NotImplemented - return self.__class__(quo, self.domain) + return self.__class__(quo, self.domain, self.window) def __rfloordiv__(self, other) : try : quo, rem = ${nick}div(other, self.coef) except : return NotImplemented - return self.__class__(quo, self.domain) + return self.__class__(quo, self.domain, self.window) def __rmod__(self, other) : try : quo, rem = ${nick}div(other, self.coef) except : return NotImplemented - return self.__class__(rem, self.domain) + return self.__class__(rem, self.domain, self.window) def __rdivmod__(self, other) : try : quo, rem = ${nick}div(other, self.coef) except : return NotImplemented - return self.__class__(quo, self.domain), self.__class__(rem, self.domain) + quo = self.__class__(quo, self.domain, self.window) + rem = self.__class__(rem, self.domain, self.window) + return quo, rem # Enhance me # some augmented arithmetic operations could be added here def __eq__(self, other) : res = isinstance(other, self.__class__) \ - and len(self.coef) == len(other.coef) \ - and np.all(self.domain == other.domain) \ - and np.all(self.coef == other.coef) + and self.has_samecoef(other) \ + and self.has_samedomain(other) \ + and self.has_samewindow(other) return res def __ne__(self, other) : return not self.__eq__(other) # - # Extra numeric functions. + # Extra methods. # + def copy(self) : + """Return a copy. + + A new instance of $name is returned that has the same + coefficients and domain as the current instance. + + Returns + ------- + new_instance : $name + New instance of $name with the same coefficients and domain. + + """ + return self.__class__(self.coef, self.domain, self.window) + def degree(self) : """The degree of the series. @@ -340,68 +456,6 @@ class $name(pu.PolyBase) : """ return self.truncate(deg + 1) - def convert(self, domain=None, kind=None) : - """Convert to different class and/or domain. - - Parameters - ---------- - domain : array_like, optional - The domain of the new series type instance. If the value is None, - then the default domain of `kind` is used. - kind : class, optional - The polynomial series type class to which the current instance - should be converted. If kind is None, then the class of the - current instance is used. - - Returns - ------- - new_series_instance : `kind` - The returned class can be of different type than the current - instance and/or have a different domain. - - Notes - ----- - Conversion between domains and class types can result in - numerically ill defined series. - - Examples - -------- - - """ - if kind is None : - kind = $name - if domain is None : - domain = kind.domain - return self(kind.identity(domain)) - - def mapparms(self) : - """Return the mapping parameters. - - The returned values define a linear map ``off + scl*x`` that is - applied to the input arguments before the series is evaluated. The - of the map depend on the domain; if the current domain is equal to - the default domain ``$domain`` the resulting map is the identity. - If the coeffients of the ``$name`` instance are to be used - separately, then the linear function must be substituted for the - ``x`` in the standard representation of the base polynomials. - - Returns - ------- - off, scl : floats or complex - The mapping function is defined by ``off + scl*x``. - - Notes - ----- - If the current domain is the interval ``[l_1, r_1]`` and the default - interval is ``[l_2, r_2]``, then the linear mapping function ``L`` is - defined by the equations:: - - L(l_1) = l_2 - L(r_1) = r_2 - - """ - return pu.mapparms(self.domain, $domain) - def trim(self, tol=0) : """Remove small leading coefficients @@ -422,7 +476,8 @@ class $name(pu.PolyBase) : Contains the new set of coefficients. """ - return self.__class__(pu.trimcoef(self.coef, tol), self.domain) + coef = pu.trimcoef(self.coef, tol) + return self.__class__(coef, self.domain, self.window) def truncate(self, size) : """Truncate series to length `size`. @@ -448,23 +503,75 @@ class $name(pu.PolyBase) : if isize != size or isize < 1 : raise ValueError("size must be a positive integer") if isize >= len(self.coef) : - return self.__class__(self.coef, self.domain) + coef = self.coef else : - return self.__class__(self.coef[:isize], self.domain) + coef = self.coef[:isize] + return self.__class__(coef, self.domain, self.window) - def copy(self) : - """Return a copy. + def convert(self, domain=None, kind=None, window=None) : + """Convert to different class and/or domain. - A new instance of $name is returned that has the same - coefficients and domain as the current instance. + Parameters + ---------- + domain : array_like, optional + The domain of the new series type instance. If the value is None, + then the default domain of `kind` is used. + kind : class, optional + The polynomial series type class to which the current instance + should be converted. If kind is None, then the class of the + current instance is used. Returns ------- - new_instance : $name - New instance of $name with the same coefficients and domain. + new_series_instance : `kind` + The returned class can be of different type than the current + instance and/or have a different domain. + + Notes + ----- + Conversion between domains and class types can result in + numerically ill defined series. + + Examples + -------- + + """ + if kind is None: + kind = $name + if domain is None: + domain = kind.domain + if window is None: + window = kind.window + return self(kind.identity(domain, window=window)) + + def mapparms(self) : + """Return the mapping parameters. + + The returned values define a linear map ``off + scl*x`` that is + applied to the input arguments before the series is evaluated. The + map depends on the ``domain`` and ``window``; if the current + ``domain`` is equal to the ``window`` the resulting map is the + identity. If the coeffients of the ``$name`` instance are to be + used by themselves outside this class, then the linear function + must be substituted for the ``x`` in the standard representation of + the base polynomials. + + Returns + ------- + off, scl : floats or complex + The mapping function is defined by ``off + scl*x``. + + Notes + ----- + If the current domain is the interval ``[l_1, r_1]`` and the window + is ``[l_2, r_2]``, then the linear mapping function ``L`` is + defined by the equations:: + + L(l_1) = l_2 + L(r_1) = r_2 """ - return self.__class__(self.coef, self.domain) + return pu.mapparms(self.domain, self.window) def integ(self, m=1, k=[], lbnd=None) : """Integrate. @@ -501,7 +608,7 @@ class $name(pu.PolyBase) : else : lbnd = off + scl*lbnd coef = ${nick}int(self.coef, m, k, lbnd, 1./scl) - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def deriv(self, m=1): """Differentiate. @@ -527,7 +634,7 @@ class $name(pu.PolyBase) : """ off, scl = self.mapparms() coef = ${nick}der(self.coef, m, scl) - return self.__class__(coef, self.domain) + return self.__class__(coef, self.domain, self.window) def roots(self) : """Return list of roots. @@ -543,9 +650,9 @@ class $name(pu.PolyBase) : """ roots = ${nick}roots(self.coef) - return pu.mapdomain(roots, $domain, self.domain) + return pu.mapdomain(roots, self.window, self.domain) - def linspace(self, n=100): + def linspace(self, n=100, domain=None): """Return x,y values at equally spaced points in domain. Returns x, y values at `n` equally spaced points across domain. @@ -566,14 +673,17 @@ class $name(pu.PolyBase) : .. versionadded:: 1.5.0 """ - x = np.linspace(self.domain[0], self.domain[1], n) + if domain is None: + domain = self.domain + x = np.linspace(domain[0], domain[1], n) y = self(x) return x, y @staticmethod - def fit(x, y, deg, domain=None, rcond=None, full=False, w=None) : + def fit(x, y, deg, domain=None, rcond=None, full=False, w=None, + window=$domain): """Least squares fit to data. Return a `$name` instance that is the least squares fit to the data @@ -616,6 +726,10 @@ class $name(pu.PolyBase) : ``w[i]*y[i]`` all have the same variance. The default value is None. .. versionadded:: 1.5.0 + window : {[beg, end]}, optional + Window to use for the returned $name instance. The default + value is ``$domain`` + .. versionadded:: 1.6.0 Returns ------- @@ -634,21 +748,25 @@ class $name(pu.PolyBase) : ${nick}fit : similar function """ - if domain is None : + if domain is None: domain = pu.getdomain(x) - elif domain == [] : + elif domain == []: domain = $domain - xnew = pu.mapdomain(x, domain, $domain) + + if window == []: + window = $domain + + xnew = pu.mapdomain(x, domain, window) res = ${nick}fit(xnew, y, deg, w=w, rcond=rcond, full=full) if full : [coef, status] = res - return $name(coef, domain=domain), status + return $name(coef, domain=domain, window=window), status else : coef = res - return $name(coef, domain=domain) + return $name(coef, domain=domain, window=window) @staticmethod - def fromroots(roots, domain=$domain) : + def fromroots(roots, domain=$domain, window=$domain) : """Return $name object with specified roots. See ${nick}fromroots for full documentation. @@ -660,12 +778,12 @@ class $name(pu.PolyBase) : """ if domain is None : domain = pu.getdomain(roots) - rnew = pu.mapdomain(roots, domain, $domain) + rnew = pu.mapdomain(roots, domain, window) coef = ${nick}fromroots(rnew) - return $name(coef, domain=domain) + return $name(coef, domain=domain, window=window) @staticmethod - def identity(domain=$domain) : + def identity(domain=$domain, window=$domain) : """Identity function. If ``p`` is the returned $name object, then ``p(x) == x`` for all @@ -676,13 +794,16 @@ class $name(pu.PolyBase) : domain : array_like The resulting array must be if the form ``[beg, end]``, where ``beg`` and ``end`` are the endpoints of the domain. + window : array_like + The resulting array must be if the form ``[beg, end]``, where + ``beg`` and ``end`` are the endpoints of the window. Returns ------- identity : $name object """ - off, scl = pu.mapparms($domain, domain) + off, scl = pu.mapparms(window, domain) coef = ${nick}line(off, scl) - return $name(coef, domain) + return $name(coef, domain, window) '''.replace('REL_IMPORT', rel_import)) |