summaryrefslogtreecommitdiff
path: root/numpy/polynomial/polynomial.py
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/polynomial/polynomial.py')
-rw-r--r--numpy/polynomial/polynomial.py229
1 files changed, 28 insertions, 201 deletions
diff --git a/numpy/polynomial/polynomial.py b/numpy/polynomial/polynomial.py
index 69599e3fd..afa330502 100644
--- a/numpy/polynomial/polynomial.py
+++ b/numpy/polynomial/polynomial.py
@@ -188,21 +188,7 @@ def polyfromroots(roots):
array([1.+0.j, 0.+0.j, 1.+0.j])
"""
- if len(roots) == 0:
- return np.ones(1)
- else:
- [roots] = pu.as_series([roots], trim=False)
- roots.sort()
- p = [polyline(-r, 1) for r in roots]
- n = len(p)
- while n > 1:
- m, r = divmod(n, 2)
- tmp = [polymul(p[i], p[i+m]) for i in range(m)]
- if r:
- tmp[0] = polymul(tmp[0], p[-1])
- p = tmp
- n = m
- return p[0]
+ return pu._fromroots(polyline, polymul, roots)
def polyadd(c1, c2):
@@ -238,15 +224,7 @@ def polyadd(c1, c2):
28.0
"""
- # c1, c2 are trimmed copies
- [c1, c2] = pu.as_series([c1, c2])
- if len(c1) > len(c2):
- c1[:c2.size] += c2
- ret = c1
- else:
- c2[:c1.size] += c1
- ret = c2
- return pu.trimseq(ret)
+ return pu._add(c1, c2)
def polysub(c1, c2):
@@ -283,16 +261,7 @@ def polysub(c1, c2):
array([ 2., 0., -2.])
"""
- # c1, c2 are trimmed copies
- [c1, c2] = pu.as_series([c1, c2])
- if len(c1) > len(c2):
- c1[:c2.size] -= c2
- ret = c1
- else:
- c2 = -c2
- c2[:c1.size] += c1
- ret = c2
- return pu.trimseq(ret)
+ return pu._sub(c1, c2)
def polymulx(c):
@@ -411,18 +380,19 @@ def polydiv(c1, c2):
if c2[-1] == 0:
raise ZeroDivisionError()
- len1 = len(c1)
- len2 = len(c2)
- if len2 == 1:
- return c1/c2[-1], c1[:1]*0
- elif len1 < len2:
+ # note: this is more efficient than `pu._div(polymul, c1, c2)`
+ lc1 = len(c1)
+ lc2 = len(c2)
+ if lc1 < lc2:
return c1[:1]*0, c1
+ elif lc2 == 1:
+ return c1/c2[-1], c1[:1]*0
else:
- dlen = len1 - len2
+ dlen = lc1 - lc2
scl = c2[-1]
c2 = c2[:-1]/scl
i = dlen
- j = len1 - 1
+ j = lc1 - 1
while i >= 0:
c1[i:j] -= c2*c1[j]
i -= 1
@@ -464,24 +434,9 @@ def polypow(c, pow, maxpower=None):
array([ 1., 4., 10., 12., 9.])
"""
- # c is a trimmed copy
- [c] = pu.as_series([c])
- power = int(pow)
- if power != pow or power < 0:
- raise ValueError("Power must be a non-negative integer.")
- elif maxpower is not None and power > maxpower:
- raise ValueError("Power is too large")
- elif power == 0:
- return np.array([1], dtype=c.dtype)
- elif power == 1:
- return c
- else:
- # This can be made more efficient by using powers of two
- # in the usual way.
- prd = c
- for i in range(2, power + 1):
- prd = np.convolve(prd, c)
- return prd
+ # note: this is more efficient than `pu._pow(polymul, c1, c2)`, as it
+ # avoids calling `as_series` repeatedly
+ return pu._pow(np.convolve, c, pow, maxpower)
def polyder(c, m=1, scl=1, axis=0):
@@ -541,14 +496,10 @@ def polyder(c, m=1, scl=1, axis=0):
# astype fails with NA
c = c + 0.0
cdt = c.dtype
- cnt, iaxis = [int(t) for t in [m, axis]]
-
- if cnt != m:
- raise ValueError("The order of derivation must be integer")
+ cnt = pu._deprecate_as_int(m, "the order of derivation")
+ iaxis = pu._deprecate_as_int(axis, "the axis")
if cnt < 0:
raise ValueError("The order of derivation must be non-negative")
- if iaxis != axis:
- raise ValueError("The axis must be integer")
iaxis = normalize_axis_index(iaxis, c.ndim)
if cnt == 0:
@@ -655,10 +606,8 @@ def polyint(c, m=1, k=[], lbnd=0, scl=1, axis=0):
cdt = c.dtype
if not np.iterable(k):
k = [k]
- cnt, iaxis = [int(t) for t in [m, axis]]
-
- if cnt != m:
- raise ValueError("The order of integration must be integer")
+ cnt = pu._deprecate_as_int(m, "the order of integration")
+ iaxis = pu._deprecate_as_int(axis, "the axis")
if cnt < 0:
raise ValueError("The order of integration must be non-negative")
if len(k) > cnt:
@@ -667,8 +616,6 @@ def polyint(c, m=1, k=[], lbnd=0, scl=1, axis=0):
raise ValueError("lbnd must be a scalar.")
if np.ndim(scl) != 0:
raise ValueError("scl must be a scalar.")
- if iaxis != axis:
- raise ValueError("The axis must be integer")
iaxis = normalize_axis_index(iaxis, c.ndim)
if cnt == 0:
@@ -924,14 +871,7 @@ def polyval2d(x, y, c):
.. versionadded:: 1.7.0
"""
- try:
- x, y = np.array((x, y), copy=0)
- except Exception:
- raise ValueError('x, y are incompatible')
-
- c = polyval(x, c)
- c = polyval(y, c, tensor=False)
- return c
+ return pu._valnd(polyval, c, x, y)
def polygrid2d(x, y, c):
@@ -984,9 +924,7 @@ def polygrid2d(x, y, c):
.. versionadded:: 1.7.0
"""
- c = polyval(x, c)
- c = polyval(y, c)
- return c
+ return pu._gridnd(polyval, c, x, y)
def polyval3d(x, y, z, c):
@@ -1037,15 +975,7 @@ def polyval3d(x, y, z, c):
.. versionadded:: 1.7.0
"""
- try:
- x, y, z = np.array((x, y, z), copy=0)
- except Exception:
- raise ValueError('x, y, z are incompatible')
-
- c = polyval(x, c)
- c = polyval(y, c, tensor=False)
- c = polyval(z, c, tensor=False)
- return c
+ return pu._valnd(polyval, c, x, y, z)
def polygrid3d(x, y, z, c):
@@ -1101,10 +1031,7 @@ def polygrid3d(x, y, z, c):
.. versionadded:: 1.7.0
"""
- c = polyval(x, c)
- c = polyval(y, c)
- c = polyval(z, c)
- return c
+ return pu._gridnd(polyval, c, x, y, z)
def polyvander(x, deg):
@@ -1145,9 +1072,7 @@ def polyvander(x, deg):
polyvander2d, polyvander3d
"""
- ideg = int(deg)
- if ideg != deg:
- raise ValueError("deg must be integer")
+ ideg = pu._deprecate_as_int(deg, "deg")
if ideg < 0:
raise ValueError("deg must be non-negative")
@@ -1208,19 +1133,7 @@ def polyvander2d(x, y, deg):
polyvander, polyvander3d. polyval2d, polyval3d
"""
- ideg = [int(d) for d in deg]
- is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)]
- if is_valid != [1, 1]:
- raise ValueError("degrees must be non-negative integers")
- degx, degy = ideg
- x, y = np.array((x, y), copy=0) + 0.0
-
- vx = polyvander(x, degx)
- vy = polyvander(y, degy)
- v = vx[..., None]*vy[..., None,:]
- # einsum bug
- #v = np.einsum("...i,...j->...ij", vx, vy)
- return v.reshape(v.shape[:-2] + (-1,))
+ return pu._vander2d(polyvander, x, y, deg)
def polyvander3d(x, y, z, deg):
@@ -1274,20 +1187,7 @@ def polyvander3d(x, y, z, deg):
.. versionadded:: 1.7.0
"""
- ideg = [int(d) for d in deg]
- is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)]
- if is_valid != [1, 1, 1]:
- raise ValueError("degrees must be non-negative integers")
- degx, degy, degz = ideg
- x, y, z = np.array((x, y, z), copy=0) + 0.0
-
- vx = polyvander(x, degx)
- vy = polyvander(y, degy)
- vz = polyvander(z, degz)
- v = vx[..., None, None]*vy[..., None,:, None]*vz[..., None, None,:]
- # einsum bug
- #v = np.einsum("...i, ...j, ...k->...ijk", vx, vy, vz)
- return v.reshape(v.shape[:-3] + (-1,))
+ return pu._vander3d(polyvander, x, y, z, deg)
def polyfit(x, y, deg, rcond=None, full=False, w=None):
@@ -1433,81 +1333,7 @@ def polyfit(x, y, deg, rcond=None, full=False, w=None):
0.50443316, 0.28853036]), 1.1324274851176597e-014]
"""
- x = np.asarray(x) + 0.0
- y = np.asarray(y) + 0.0
- deg = np.asarray(deg)
-
- # check arguments.
- if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0:
- raise TypeError("deg must be an int or non-empty 1-D array of int")
- if deg.min() < 0:
- raise ValueError("expected deg >= 0")
- if x.ndim != 1:
- raise TypeError("expected 1D vector for x")
- if x.size == 0:
- raise TypeError("expected non-empty vector for x")
- if y.ndim < 1 or y.ndim > 2:
- raise TypeError("expected 1D or 2D array for y")
- if len(x) != len(y):
- raise TypeError("expected x and y to have same length")
-
- if deg.ndim == 0:
- lmax = deg
- order = lmax + 1
- van = polyvander(x, lmax)
- else:
- deg = np.sort(deg)
- lmax = deg[-1]
- order = len(deg)
- van = polyvander(x, lmax)[:, deg]
-
- # set up the least squares matrices in transposed form
- lhs = van.T
- rhs = y.T
- if w is not None:
- w = np.asarray(w) + 0.0
- if w.ndim != 1:
- raise TypeError("expected 1D vector for w")
- if len(x) != len(w):
- raise TypeError("expected x and w to have same length")
- # apply weights. Don't use inplace operations as they
- # can cause problems with NA.
- lhs = lhs * w
- rhs = rhs * w
-
- # set rcond
- if rcond is None:
- rcond = len(x)*np.finfo(x.dtype).eps
-
- # Determine the norms of the design matrix columns.
- if issubclass(lhs.dtype.type, np.complexfloating):
- scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1))
- else:
- scl = np.sqrt(np.square(lhs).sum(1))
- scl[scl == 0] = 1
-
- # Solve the least squares problem.
- c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond)
- c = (c.T/scl).T
-
- # Expand c to include non-fitted coefficients which are set to zero
- if deg.ndim == 1:
- if c.ndim == 2:
- cc = np.zeros((lmax + 1, c.shape[1]), dtype=c.dtype)
- else:
- cc = np.zeros(lmax + 1, dtype=c.dtype)
- cc[deg] = c
- c = cc
-
- # warn on rank reduction
- if rank != order and not full:
- msg = "The fit may be poorly conditioned"
- warnings.warn(msg, pu.RankWarning, stacklevel=2)
-
- if full:
- return c, [resids, rank, s, rcond]
- else:
- return c
+ return pu._fit(polyvander, x, y, deg, rcond, full, w)
def polycompanion(c):
@@ -1602,7 +1428,8 @@ def polyroots(c):
if len(c) == 2:
return np.array([-c[0]/c[1]])
- m = polycompanion(c)
+ # rotated companion matrix reduces error
+ m = polycompanion(c)[::-1,::-1]
r = la.eigvals(m)
r.sort()
return r