summaryrefslogtreecommitdiff
path: root/scipy/base/polynomial.py
diff options
context:
space:
mode:
Diffstat (limited to 'scipy/base/polynomial.py')
-rw-r--r--scipy/base/polynomial.py230
1 files changed, 119 insertions, 111 deletions
diff --git a/scipy/base/polynomial.py b/scipy/base/polynomial.py
index 98a1903a3..0160626d4 100644
--- a/scipy/base/polynomial.py
+++ b/scipy/base/polynomial.py
@@ -1,10 +1,15 @@
-## Automatically adapted for scipy Sep 19, 2005 by convertcode.py
+"""
+Functions to operate on polynomials.
+"""
-import numeric
-_nx = numeric
-from numeric import *
-from scimath import *
+# FIXME: this module still uses Numeric typechars
+__all__ = ['poly', 'roots', 'polyint', 'polyder', 'polyadd',
+ 'polysub', 'polymul', 'polydiv', 'polyval', 'poly1d',
+ 'polyfit']
+
+import re
+import numeric as NX
from type_check import isscalar
from twodim_base import diag, vander
@@ -14,6 +19,7 @@ eigvals = None
lstsq = None
def get_linalg_funcs():
+ "Look for linear algebra functions in scipy"
global eigvals, lstsq
import scipy
eigvals = scipy.linalg.eigvals
@@ -21,39 +27,36 @@ def get_linalg_funcs():
return
def _eigvals(arg):
+ "Return the eigenvalues of the argument"
try:
return eigvals(arg)
except TypeError:
get_linalg_funcs()
return eigvals(arg)
-def _lstsq(*args):
+def _lstsq(X, y):
+ "Do least squares on the arguments"
try:
- return lstsq(*args)
+ return lstsq(X, y)
except TypeError:
get_linalg_funcs()
- return lstsq(*args)
-
-
-__all__ = ['poly','roots','polyint','polyder','polyadd','polysub','polymul',
- 'polydiv','polyval','poly1d','polyfit']
-
+ return lstsq(X, y)
def poly(seq_of_zeros):
""" Return a sequence representing a polynomial given a sequence of roots.
If the input is a matrix, return the characteristic polynomial.
-
+
Example:
-
+
>>> b = roots([1,3,1,5,6])
>>> poly(b)
array([1., 3., 1., 5., 6.])
"""
seq_of_zeros = atleast_1d(seq_of_zeros)
- sh = shape(seq_of_zeros)
+ sh = NX.shape(seq_of_zeros)
if len(sh) == 2 and sh[0] == sh[1]:
- seq_of_zeros=_eigvals(seq_of_zeros)
+ seq_of_zeros = _eigvals(seq_of_zeros)
elif len(sh) ==1:
pass
else:
@@ -64,15 +67,16 @@ def poly(seq_of_zeros):
a = [1]
for k in range(len(seq_of_zeros)):
- a = convolve(a,[1, -seq_of_zeros[k]], mode=2)
-
- if a.dtypechar in ['F','D']:
+ a = NX.convolve(a, [1, -seq_of_zeros[k]], mode=2)
+
+ if a.dtypechar in ['F', 'D']:
# if complex roots are all complex conjugates, the roots are real.
- roots = asarray(seq_of_zeros,'D')
- pos_roots = sort_complex(compress(roots.imag > 0,roots))
- neg_roots = conjugate(sort_complex(compress(roots.imag < 0,roots)))
+ roots = NX.asarray(seq_of_zeros, 'D')
+ pos_roots = sort_complex(NX.compress(roots.imag > 0, roots))
+ neg_roots = NX.conjugate(sort_complex(
+ NX.compress(roots.imag < 0,roots)))
if (len(pos_roots) == len(neg_roots) and
- alltrue(neg_roots == pos_roots)):
+ NX.alltrue(neg_roots == pos_roots)):
a = a.real.copy()
return a
@@ -88,34 +92,34 @@ def roots(p):
p = atleast_1d(p)
if len(p.shape) != 1:
raise ValueError,"Input must be a rank-1 array."
-
+
# find non-zero array entries
- non_zero = nonzero(ravel(p))
+ non_zero = NX.nonzero(NX.ravel(p))
# find the number of trailing zeros -- this is the number of roots at 0.
trailing_zeros = len(p) - non_zero[-1] - 1
# strip leading and trailing zeros
p = p[int(non_zero[0]):int(non_zero[-1])+1]
-
+
# casting: if incoming array isn't floating point, make it floating point.
- if p.dtypechar not in ['f','d','F','D']:
+ if p.dtypechar not in ['f', 'd', 'F', 'D']:
p = p.astype('d')
N = len(p)
if N > 1:
# build companion matrix and find its eigenvalues (the roots)
- A = diag(ones((N-2,),p.dtypechar),-1)
- A[0,:] = -p[1:] / p[0]
+ A = diag(NX.ones((N-2,), p.dtypechar), -1)
+ A[0, :] = -p[1:] / p[0]
roots = _eigvals(A)
else:
- return array([])
+ return NX.array([])
- # tack any zeros onto the back of the array
- roots = hstack((roots,zeros(trailing_zeros,roots.dtypechar)))
+ # tack any zeros onto the back of the array
+ roots = hstack((roots, NX.zeros(trailing_zeros, roots.dtypechar)))
return roots
-def polyint(p,m=1,k=None):
+def polyint(p, m=1, k=None):
"""Return the mth analytical integral of the polynomial p.
If k is None, then zero-valued constants of integration are used.
@@ -127,45 +131,45 @@ def polyint(p,m=1,k=None):
if m < 0:
raise ValueError, "Order of integral must be positive (see polyder)"
if k is None:
- k = _nx.zeros(m)
+ k = NX.zeros(m)
k = atleast_1d(k)
if len(k) == 1 and m > 1:
- k = k[0]*_nx.ones(m)
+ k = k[0]*NX.ones(m)
if len(k) < m:
raise ValueError, \
"k must be a scalar or a rank-1 array of length 1 or >m."
if m == 0:
return p
else:
- truepoly = isinstance(p,poly1d)
- p = asarray(p)
- y = _nx.zeros(len(p)+1,'d')
- y[:-1] = p*1.0/_nx.arange(len(p),0,-1)
- y[-1] = k[0]
- val = polyint(y,m-1,k=k[1:])
+ truepoly = isinstance(p, poly1d)
+ p = NX.asarray(p)
+ y = NX.zeros(len(p)+1, 'd')
+ y[:-1] = p*1.0/NX.arange(len(p), 0, -1)
+ y[-1] = k[0]
+ val = polyint(y, m-1, k=k[1:])
if truepoly:
val = poly1d(val)
return val
-
-def polyder(p,m=1):
+
+def polyder(p, m=1):
"""Return the mth derivative of the polynomial p.
"""
m = int(m)
- truepoly = isinstance(p,poly1d)
- p = asarray(p)
+ truepoly = isinstance(p, poly1d)
+ p = NX.asarray(p)
n = len(p)-1
- y = p[:-1] * _nx.arange(n,0,-1)
+ y = p[:-1] * NX.arange(n, 0, -1)
if m < 0:
raise ValueError, "Order of derivative must be positive (see polyint)"
if m == 0:
return p
else:
- val = polyder(y,m-1)
+ val = polyder(y, m-1)
if truepoly:
val = poly1d(val)
return val
-def polyfit(x,y,N):
+def polyfit(x, y, N):
"""
Do a best fit polynomial of order N of y to x. Return value is a
@@ -201,17 +205,17 @@ def polyfit(x,y,N):
See also polyval
"""
- x = asarray(x)+0.
- y = asarray(y)+0.
- y = reshape(y, (len(y),1))
+ x = NX.asarray(x)+0.
+ y = NX.asarray(y)+0.
+ y = NX.reshape(y, (len(y), 1))
X = vander(x, N+1)
- c,resids,rank,s = _lstsq(X,y)
+ c, resids, rank, s = _lstsq(X, y)
c.shape = (N+1,)
return c
-def polyval(p,x):
+def polyval(p, x):
"""Evaluate the polynomial p at x. If x is a polynomial then composition.
Description:
@@ -226,58 +230,58 @@ def polyval(p,x):
Notice: This can produce inaccurate results for polynomials with significant
variability. Use carefully.
"""
- p = asarray(p)
- if isinstance(x,poly1d):
+ p = NX.asarray(p)
+ if isinstance(x, poly1d):
y = 0
else:
- x = asarray(x)
- y = _nx.zeros(x.shape,x.dtypechar)
+ x = NX.asarray(x)
+ y = NX.zeros(x.shape, x.dtypechar)
for i in range(len(p)):
y = x * y + p[i]
return y
-def polyadd(a1,a2):
+def polyadd(a1, a2):
"""Adds two polynomials represented as sequences
"""
- truepoly = (isinstance(a1,poly1d) or isinstance(a2,poly1d))
- a1,a2 = map(atleast_1d,(a1,a2))
+ truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
+ a1, a2 = map(atleast_1d, (a1, a2))
diff = len(a2) - len(a1)
if diff == 0:
return a1 + a2
elif diff > 0:
- zr = _nx.zeros(diff)
- val = _nx.concatenate((zr,a1)) + a2
+ zr = NX.zeros(diff)
+ val = NX.concatenate((zr, a1)) + a2
else:
- zr = _nx.zeros(abs(diff))
- val = a1 + _nx.concatenate((zr,a2))
+ zr = NX.zeros(abs(diff))
+ val = a1 + NX.concatenate((zr, a2))
if truepoly:
val = poly1d(val)
return val
-def polysub(a1,a2):
+def polysub(a1, a2):
"""Subtracts two polynomials represented as sequences
"""
- truepoly = (isinstance(a1,poly1d) or isinstance(a2,poly1d))
- a1,a2 = map(atleast_1d,(a1,a2))
+ truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
+ a1, a2 = map(atleast_1d, (a1, a2))
diff = len(a2) - len(a1)
if diff == 0:
return a1 - a2
elif diff > 0:
- zr = _nx.zeros(diff)
- val = _nx.concatenate((zr,a1)) - a2
+ zr = NX.zeros(diff)
+ val = NX.concatenate((zr, a1)) - a2
else:
- zr = _nx.zeros(abs(diff))
- val = a1 - _nx.concatenate((zr,a2))
+ zr = NX.zeros(abs(diff))
+ val = a1 - NX.concatenate((zr, a2))
if truepoly:
val = poly1d(val)
return val
-def polymul(a1,a2):
+def polymul(a1, a2):
"""Multiplies two polynomials represented as sequences.
"""
- truepoly = (isinstance(a1,poly1d) or isinstance(a2,poly1d))
- val = _nx.convolve(a1,a2)
+ truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
+ val = NX.convolve(a1, a2)
if truepoly:
val = poly1d(val)
return val
@@ -288,7 +292,7 @@ def deconvolve(signal, divisor):
"""
try:
import scipy.signal
- except:
+ except ImportError:
print "You need scipy.signal to use this function."
num = atleast_1d(signal)
den = atleast_1d(divisor)
@@ -298,25 +302,24 @@ def deconvolve(signal, divisor):
quot = [];
rem = num;
else:
- input = _nx.ones(N-D+1,_nx.Float)
+ input = NX.ones(N-D+1, NX.Float)
input[1:] = 0
quot = scipy.signal.lfilter(num, den, input)
- rem = num - _nx.convolve(den,quot,mode=2)
+ rem = num - NX.convolve(den, quot, mode=2)
return quot, rem
-def polydiv(a1,a2):
+def polydiv(a1, a2):
"""Computes q and r polynomials so that a1(s) = q(s)*a2(s) + r(s)
"""
- truepoly = (isinstance(a1,poly1d) or isinstance(a2,poly1d))
- q, r = deconvolve(a1,a2)
- while _nx.allclose(r[0], 0, rtol=1e-14) and (r.shape[-1] > 1):
+ truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d))
+ q, r = deconvolve(a1, a2)
+ while NX.allclose(r[0], 0, rtol=1e-14) and (r.shape[-1] > 1):
r = r[1:]
if truepoly:
- q, r = map(poly1d,(q,r))
+ q, r = map(poly1d, (q, r))
return q, r
-import re
_poly_mat = re.compile(r"[*][*]([0-9]*)")
def _raise_power(astr, wrap=70):
n = 0
@@ -324,7 +327,7 @@ def _raise_power(astr, wrap=70):
line2 = ''
output = ' '
while 1:
- mat = _poly_mat.search(astr,n)
+ mat = _poly_mat.search(astr, n)
if mat is None:
break
span = mat.span()
@@ -338,14 +341,14 @@ def _raise_power(astr, wrap=70):
output += line1 + "\n" + line2 + "\n "
line1 = toadd1
line2 = toadd2
- else:
+ else:
line2 += partstr + ' '*(len(power)-1)
line1 += ' '*(len(partstr)-1) + power
output += line1 + "\n" + line2
return output + astr[n:]
-
-
-class poly1d:
+
+
+class poly1d(object):
"""A one-dimensional polynomial class.
p = poly1d([1,2,3]) constructs the polynomial x**2 + 2 x + 3
@@ -363,7 +366,7 @@ class poly1d:
be used in all functions that accept arrays.
"""
def __init__(self, c_or_r, r=0):
- if isinstance(c_or_r,poly1d):
+ if isinstance(c_or_r, poly1d):
for key in c_or_r.__dict__.keys():
self.__dict__[key] = c_or_r.__dict__[key]
return
@@ -374,19 +377,19 @@ class poly1d:
raise ValueError, "Polynomial must be 1d only."
c_or_r = trim_zeros(c_or_r, trim='f')
if len(c_or_r) == 0:
- c_or_r = _nx.array([0])
+ c_or_r = NX.array([0])
self.__dict__['coeffs'] = c_or_r
self.__dict__['order'] = len(c_or_r) - 1
- def __array__(self,t=None):
+ def __array__(self, t=None):
if t:
- return asarray(self.coeffs,t)
+ return NX.asarray(self.coeffs, t)
else:
- return asarray(self.coeffs)
+ return NX.asarray(self.coeffs)
- def __coerce__(self,other):
+ def __coerce__(self, other):
return None
-
+
def __repr__(self):
vals = repr(self.coeffs)
vals = vals[6:-1]
@@ -416,14 +419,14 @@ class poly1d:
newstr = ''
elif coefstr == 'b':
newstr = 'x'
- else:
+ else:
newstr = '%s x' % (coefstr,)
else:
if coefstr == '0':
newstr = ''
elif coefstr == 'b':
newstr = 'x**%d' % (power,)
- else:
+ else:
newstr = '%s x**%d' % (coefstr, power)
if k > 0:
@@ -437,7 +440,7 @@ class poly1d:
else:
thestr = newstr
return _raise_power(thestr)
-
+
def __call__(self, val):
return polyval(self.coeffs, val)
@@ -454,12 +457,12 @@ class poly1d:
return poly1d(other * self.coeffs)
else:
other = poly1d(other)
- return poly1d(polymul(self.coeffs, other.coeffs))
-
+ return poly1d(polymul(self.coeffs, other.coeffs))
+
def __add__(self, other):
other = poly1d(other)
- return poly1d(polyadd(self.coeffs, other.coeffs))
-
+ return poly1d(polyadd(self.coeffs, other.coeffs))
+
def __radd__(self, other):
other = poly1d(other)
return poly1d(polyadd(self.coeffs, other.coeffs))
@@ -485,20 +488,20 @@ class poly1d:
return poly1d(self.coeffs/other)
else:
other = poly1d(other)
- return map(poly1d,polydiv(self.coeffs, other.coeffs))
+ return map(poly1d, polydiv(self.coeffs, other.coeffs))
def __rdiv__(self, other):
if isscalar(other):
return poly1d(other/self.coeffs)
else:
other = poly1d(other)
- return map(poly1d,polydiv(other.coeffs, self.coeffs))
+ return map(poly1d, polydiv(other.coeffs, self.coeffs))
def __setattr__(self, key, val):
raise ValueError, "Attributes cannot be changed this way."
def __getattr__(self, key):
- if key in ['r','roots']:
+ if key in ['r', 'roots']:
return roots(self.coeffs)
elif key in ['c','coef','coefficients']:
return self.coeffs
@@ -506,7 +509,7 @@ class poly1d:
return self.order
else:
return self.__dict__[key]
-
+
def __getitem__(self, val):
ind = self.order - val
if val > self.order:
@@ -520,15 +523,20 @@ class poly1d:
if key < 0:
raise ValueError, "Does not support negative powers."
if key > self.order:
- zr = _nx.zeros(key-self.order,self.coeffs.dtypechar)
- self.__dict__['coeffs'] = _nx.concatenate((zr,self.coeffs))
+ zr = NX.zeros(key-self.order, self.coeffs.dtypechar)
+ self.__dict__['coeffs'] = NX.concatenate((zr, self.coeffs))
self.__dict__['order'] = key
ind = 0
self.__dict__['coeffs'][ind] = val
return
def integ(self, m=1, k=0):
- return poly1d(polyint(self.coeffs,m=m,k=k))
+ """Return the mth analytical integral of this polynomial.
+ See the documentation for polyint.
+ """
+ return poly1d(polyint(self.coeffs, m=m, k=k))
def deriv(self, m=1):
- return poly1d(polyder(self.coeffs,m=m))
+ """Return the mth derivative of this polynomial.
+ """
+ return poly1d(polyder(self.coeffs, m=m))