diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/polynomial/_polybase.py | 221 | ||||
-rw-r--r-- | numpy/polynomial/polytemplate.py | 27 | ||||
-rw-r--r-- | numpy/polynomial/tests/test_classes.py | 76 |
3 files changed, 164 insertions, 160 deletions
diff --git a/numpy/polynomial/_polybase.py b/numpy/polynomial/_polybase.py index 4f174891a..83119579c 100644 --- a/numpy/polynomial/_polybase.py +++ b/numpy/polynomial/_polybase.py @@ -9,6 +9,7 @@ abc module from the stdlib, hence it is only available for Python >= 2.6. from __future__ import division, absolute_import, print_function from abc import ABCMeta, abstractmethod, abstractproperty +from numbers import Number import numpy as np from . import polyutils as pu @@ -206,6 +207,42 @@ class ABCPolyBase(object): """ return isinstance(other, self.__class__) + def _get_coefficients(self, other): + """Interpret other as polynomial coefficients. + + The `other` argument is checked to see if it is of the same + class as self with identical domain and window. If so, + return its coefficients, otherwise return `other`. + + .. versionadded:: 1.9.0 + + Parameters + ---------- + other : anything + Object to be checked. + + Returns + ------- + coef: + The coefficients of`other` if it is a compatible instance, + of ABCPolyBase, otherwise `other`. + + Raises + ------ + TypeError: + When `other` is an incompatible instance of ABCPolyBase. + + """ + if isinstance(other, ABCPolyBase): + if not isinstance(other, self.__class__): + raise TypeError("Polynomial types differ") + elif not np.all(self.domain == other.domain): + raise TypeError("Domains differ") + elif not np.all(self.window == other.window): + raise TypeError("Windows differ") + return other.coef + return other + def __init__(self, coef, domain=None, window=None): [coef] = pu.as_series([coef], trim=False) self.coef = coef @@ -270,54 +307,33 @@ class ABCPolyBase(object): return self def __add__(self, other): - if isinstance(other, ABCPolyBase): - if not self.has_sametype(other): - raise TypeError("Polynomial types differ") - elif not self.has_samedomain(other): - raise TypeError("Domains differ") - elif not self.has_samewindow(other): - raise TypeError("Windows differ") - else: - coef = self._add(self.coef, other.coef) - else: - try: - coef = self._add(self.coef, other) - except: - return NotImplemented + try: + othercoef = self._get_coefficients(other) + coef = self._add(self.coef, othercoef) + except TypeError as e: + raise e + except: + return NotImplemented return self.__class__(coef, self.domain, self.window) def __sub__(self, other): - if isinstance(other, ABCPolyBase): - if not self.has_sametype(other): - raise TypeError("Polynomial types differ") - elif not self.has_samedomain(other): - raise TypeError("Domains differ") - elif not self.has_samewindow(other): - raise TypeError("Windows differ") - else: - coef = self._sub(self.coef, other.coef) - else: - try: - coef = self._sub(self.coef, other) - except: - return NotImplemented + try: + othercoef = self._get_coefficients(other) + coef = self._sub(self.coef, othercoef) + except TypeError as e: + raise e + except: + return NotImplemented return self.__class__(coef, self.domain, self.window) def __mul__(self, other): - if isinstance(other, ABCPolyBase): - if not self.has_sametype(other): - raise TypeError("Polynomial types differ") - elif not self.has_samedomain(other): - raise TypeError("Domains differ") - elif not self.has_samewindow(other): - raise TypeError("Windows differ") - else: - coef = self._mul(self.coef, other.coef) - else: - try: - coef = self._mul(self.coef, other) - except: - return NotImplemented + try: + othercoef = self._get_coefficients(other) + coef = self._mul(self.coef, othercoef) + except TypeError as e: + raise e + except: + return NotImplemented return self.__class__(coef, self.domain, self.window) def __div__(self, other): @@ -325,73 +341,42 @@ class ABCPolyBase(object): return self.__floordiv__(other) def __truediv__(self, other): - # there is no true divide if the rhs is not a scalar, although it + # there is no true divide if the rhs is not a Number, although it # could return the first n elements of an infinite series. # It is hard to see where n would come from, though. - if np.isscalar(other): - # this might be overly restrictive - coef = self.coef/other - return self.__class__(coef, self.domain, self.window) - else: - return NotImplemented + if not isinstance(other, Number) or isinstance(other, bool): + form = "unsupported types for true division: '%s', '%s'" + raise TypeError(form % (type(self), type(other))) + return self.__floordiv__(other) def __floordiv__(self, other): - if isinstance(other, ABCPolyBase): - if not self.has_sametype(other): - raise TypeError("Polynomial types differ") - elif not self.has_samedomain(other): - raise TypeError("Domains differ") - elif not self.has_samewindow(other): - raise TypeError("Windows differ") - else: - quo, rem = self._div(self.coef, other.coef) - else: - try: - quo, rem = self._div(self.coef, other) - except: - return NotImplemented - return self.__class__(quo, self.domain, self.window) + res = self.__divmod__(other) + if res is NotImplemented: + return res + return res[0] def __mod__(self, other): - if isinstance(other, ABCPolyBase): - if not self.has_sametype(other): - raise TypeError("Polynomial types differ") - elif not self.has_samedomain(other): - raise TypeError("Domains differ") - elif not self.has_samewindow(other): - raise TypeError("Windows differ") - else: - quo, rem = self._div(self.coef, other.coef) - else: - try: - quo, rem = self._div(self.coef, other) - except: - return NotImplemented - return self.__class__(rem, self.domain, self.window) + res = self.__divmod__(other) + if res is NotImplemented: + return res + return res[1] def __divmod__(self, other): - if isinstance(other, self.__class__): - if not self.has_samedomain(other): - raise TypeError("Domains are not equal") - elif not self.has_samewindow(other): - raise TypeError("Windows are not equal") - else: - quo, rem = self._div(self.coef, other.coef) - else: - try: - quo, rem = self._div(self.coef, other) - except: - return NotImplemented + try: + othercoef = self._get_coefficients(other) + quo, rem = self._div(self.coef, othercoef) + except (TypeError, ZeroDivisionError) as e: + raise e + except: + return NotImplemented 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 = self._pow(self.coef, other, maxpower = self.maxpower) - except: - raise - return self.__class__(coef, self.domain, self.window) + coef = self._pow(self.coef, other, maxpower = self.maxpower) + res = self.__class__(coef, self.domain, self.window) + return res def __radd__(self, other): try: @@ -419,33 +404,27 @@ class ABCPolyBase(object): return self.__rfloordiv__(other) def __rtruediv__(self, other): - # there is no true divide if the rhs is not a scalar, although it - # could return the first n elements of an infinite series. - # It is hard to see where n would come from, though. - if len(self.coef) == 1: - try: - quo, rem = self._div(other, self.coef[0]) - except: - return NotImplemented - return self.__class__(quo, self.domain, self.window) + # An instance of ABCPolyBase is not considered a + # Number. + return NotImplemented def __rfloordiv__(self, other): - try: - quo, rem = self._div(other, self.coef) - except: - return NotImplemented - return self.__class__(quo, self.domain, self.window) + res = self.__rdivmod__(other) + if res is NotImplemented: + return res + return res[0] def __rmod__(self, other): - try: - quo, rem = self._div(other, self.coef) - except: - return NotImplemented - return self.__class__(rem, self.domain, self.window) + res = self.__rdivmod__(other) + if res is NotImplemented: + return res + return res[1] def __rdivmod__(self, other): try: quo, rem = self._div(other, self.coef) + except ZeroDivisionError as e: + raise e except: return NotImplemented quo = self.__class__(quo, self.domain, self.window) @@ -456,10 +435,10 @@ class ABCPolyBase(object): # some augmented arithmetic operations could be added here def __eq__(self, other): - res = isinstance(other, self.__class__) and\ - self.has_samecoef(other) and \ - self.has_samedomain(other) and\ - self.has_samewindow(other) + res = (isinstance(other, self.__class__) and + np.all(self.domain == other.domain) and + np.all(self.window == other.window) and + np.all(self.coef == other.coef)) return res def __ne__(self, other): @@ -813,7 +792,7 @@ class ABCPolyBase(object): """ if domain is None: domain = pu.getdomain(x) - elif domain == []: + elif isinstance(domain, list) and len(domain) == 0: domain = cls.domain if window is None: @@ -857,7 +836,7 @@ class ABCPolyBase(object): [roots] = pu.as_series([roots], trim=False) if domain is None: domain = pu.getdomain(roots) - elif domain == []: + elif isinstance(domain, list) and len(domain) == 0: domain = cls.domain if window is None: diff --git a/numpy/polynomial/polytemplate.py b/numpy/polynomial/polytemplate.py index eeacf24fb..6c60ab3b2 100644 --- a/numpy/polynomial/polytemplate.py +++ b/numpy/polynomial/polytemplate.py @@ -14,6 +14,7 @@ from __future__ import division, absolute_import, print_function import string import sys import warnings +from number import Number from numpy import ModuleDeprecationWarning @@ -287,15 +288,13 @@ class $name(pu.PolyBase) : return self.__floordiv__(other) def __truediv__(self, other) : - # there is no true divide if the rhs is not a scalar, although it + # there is no true divide if the rhs is not a Number, although it # could return the first n elements of an infinite series. # It is hard to see where n would come from, though. - if np.isscalar(other) : - # this might be overly restrictive - coef = self.coef/other - return self.__class__(coef, self.domain, self.window) - else : - return NotImplemented + if not isinstance(other, Number) or isinstance(other, bool): + form = "unsupported types for true division: '%s', '%s'" + raise TypeError(form % (type(self), type(other))) + return self.__floordiv__(other) def __floordiv__(self, other) : """Returns the quotient.""" @@ -384,20 +383,14 @@ class $name(pu.PolyBase) : return self.__rfloordiv__(other) def __rtruediv__(self, other) : - # there is no true divide if the rhs is not a scalar, although it - # could return the first n elements of an infinite series. - # It is hard to see where n would come from, though. - if len(self.coef) == 1 : - try : - quo, rem = ${nick}div(other, self.coef[0]) - except : - return NotImplemented - return self.__class__(quo, self.domain, self.window) + # An instance of PolyBase is not considered a + # Number. + return NotImplemented def __rfloordiv__(self, other) : try : quo, rem = ${nick}div(other, self.coef) - except : + except: return NotImplemented return self.__class__(quo, self.domain, self.window) diff --git a/numpy/polynomial/tests/test_classes.py b/numpy/polynomial/tests/test_classes.py index 09b30a9e9..f9134b8c1 100644 --- a/numpy/polynomial/tests/test_classes.py +++ b/numpy/polynomial/tests/test_classes.py @@ -5,6 +5,9 @@ This tests the convert and cast methods of all the polynomial classes. """ from __future__ import division, absolute_import, print_function +import operator as op +from numbers import Number + import numpy as np from numpy.polynomial import ( Polynomial, Legendre, Chebyshev, Laguerre, @@ -13,6 +16,7 @@ from numpy.testing import ( TestCase, assert_almost_equal, assert_raises, assert_equal, assert_, run_module_suite, dec) from numpy.testing.noseclasses import KnownFailure +from numpy.compat import long classes = ( @@ -37,6 +41,7 @@ def test_class_methods(): yield check_sub, Poly yield check_mul, Poly yield check_floordiv, Poly + yield check_truediv, Poly yield check_mod, Poly yield check_divmod, Poly yield check_pow, Poly @@ -221,12 +226,12 @@ def check_add(Poly): assert_poly_almost_equal(tuple(c2) + p1, p3) assert_poly_almost_equal(p1 + np.array(c2), p3) assert_poly_almost_equal(np.array(c2) + p1, p3) - assert_raises(TypeError, p1.__add__, Poly([0], domain=Poly.domain + 1)) - assert_raises(TypeError, p1.__add__, Poly([0], window=Poly.window + 1)) + assert_raises(TypeError, op.add, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, op.add, p1, Poly([0], window=Poly.window + 1)) if Poly is Polynomial: - assert_raises(TypeError, p1.__add__, Chebyshev([0])) + assert_raises(TypeError, op.add, p1, Chebyshev([0])) else: - assert_raises(TypeError, p1.__add__, Polynomial([0])) + assert_raises(TypeError, op.add, p1, Polynomial([0])) def check_sub(Poly): @@ -243,12 +248,12 @@ def check_sub(Poly): assert_poly_almost_equal(tuple(c2) - p1, -p3) assert_poly_almost_equal(p1 - np.array(c2), p3) assert_poly_almost_equal(np.array(c2) - p1, -p3) - assert_raises(TypeError, p1.__sub__, Poly([0], domain=Poly.domain + 1)) - assert_raises(TypeError, p1.__sub__, Poly([0], window=Poly.window + 1)) + assert_raises(TypeError, op.sub, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, op.sub, p1, Poly([0], window=Poly.window + 1)) if Poly is Polynomial: - assert_raises(TypeError, p1.__sub__, Chebyshev([0])) + assert_raises(TypeError, op.sub, p1, Chebyshev([0])) else: - assert_raises(TypeError, p1.__sub__, Polynomial([0])) + assert_raises(TypeError, op.sub, p1, Polynomial([0])) def check_mul(Poly): @@ -266,12 +271,12 @@ def check_mul(Poly): assert_poly_almost_equal(np.array(c2) * p1, p3) assert_poly_almost_equal(p1 * 2, p1 * Poly([2])) assert_poly_almost_equal(2 * p1, p1 * Poly([2])) - assert_raises(TypeError, p1.__mul__, Poly([0], domain=Poly.domain + 1)) - assert_raises(TypeError, p1.__mul__, Poly([0], window=Poly.window + 1)) + assert_raises(TypeError, op.mul, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, op.mul, p1, Poly([0], window=Poly.window + 1)) if Poly is Polynomial: - assert_raises(TypeError, p1.__mul__, Chebyshev([0])) + assert_raises(TypeError, op.mul, p1, Chebyshev([0])) else: - assert_raises(TypeError, p1.__mul__, Polynomial([0])) + assert_raises(TypeError, op.mul, p1, Polynomial([0])) def check_floordiv(Poly): @@ -293,13 +298,40 @@ def check_floordiv(Poly): assert_poly_almost_equal(2 // p2, Poly([0])) assert_poly_almost_equal(p2 // 2, 0.5*p2) assert_raises( - TypeError, p1.__floordiv__, Poly([0], domain=Poly.domain + 1)) + TypeError, op.floordiv, p1, Poly([0], domain=Poly.domain + 1)) assert_raises( - TypeError, p1.__floordiv__, Poly([0], window=Poly.window + 1)) + TypeError, op.floordiv, p1, Poly([0], window=Poly.window + 1)) if Poly is Polynomial: - assert_raises(TypeError, p1.__floordiv__, Chebyshev([0])) + assert_raises(TypeError, op.floordiv, p1, Chebyshev([0])) else: - assert_raises(TypeError, p1.__floordiv__, Polynomial([0])) + assert_raises(TypeError, op.floordiv, p1, Polynomial([0])) + + +def check_truediv(Poly): + # true division is valid only if the denominator is a Number and + # not a python bool. + p1 = Poly([1,2,3]) + p2 = p1 * 5 + + for stype in np.ScalarType: + if not issubclass(stype, Number) or issubclass(stype, bool): + continue + s = stype(5) + assert_poly_almost_equal(op.truediv(p2, s), p1) + assert_raises(TypeError, op.truediv, s, p2) + for stype in (int, long, float): + s = stype(5) + assert_poly_almost_equal(op.truediv(p2, s), p1) + assert_raises(TypeError, op.truediv, s, p2) + for stype in [complex]: + s = stype(5, 0) + assert_poly_almost_equal(op.truediv(p2, s), p1) + assert_raises(TypeError, op.truediv, s, p2) + for s in [tuple(), list(), dict(), bool(), np.array([1])]: + assert_raises(TypeError, op.truediv, p2, s) + assert_raises(TypeError, op.truediv, s, p2) + for ptype in classes: + assert_raises(TypeError, op.truediv, p2, ptype(1)) def check_mod(Poly): @@ -321,12 +353,12 @@ def check_mod(Poly): assert_poly_almost_equal(np.array(c4) % p2, p3) assert_poly_almost_equal(2 % p2, Poly([2])) assert_poly_almost_equal(p2 % 2, Poly([0])) - assert_raises(TypeError, p1.__mod__, Poly([0], domain=Poly.domain + 1)) - assert_raises(TypeError, p1.__mod__, Poly([0], window=Poly.window + 1)) + assert_raises(TypeError, op.mod, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, op.mod, p1, Poly([0], window=Poly.window + 1)) if Poly is Polynomial: - assert_raises(TypeError, p1.__mod__, Chebyshev([0])) + assert_raises(TypeError, op.mod, p1, Chebyshev([0])) else: - assert_raises(TypeError, p1.__mod__, Polynomial([0])) + assert_raises(TypeError, op.mod, p1, Polynomial([0])) def check_divmod(Poly): @@ -464,8 +496,8 @@ def check_pow(Poly): for i in range(5): assert_poly_almost_equal(tst**i, tgt) tgt = tgt * tst - assert_raises(ValueError, tgt.__pow__, 1.5) - assert_raises(ValueError, tgt.__pow__, -1) + assert_raises(ValueError, op.pow, tgt, 1.5) + assert_raises(ValueError, op.pow, tgt, -1) def check_call(Poly): |