summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/polynomial/_polybase.py221
-rw-r--r--numpy/polynomial/polytemplate.py27
-rw-r--r--numpy/polynomial/tests/test_classes.py76
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):