From scipy-svn at scipy.org Wed Dec 3 15:15:08 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 3 Dec 2008 14:15:08 -0600 (CST) Subject: [Scipy-svn] r5214 - trunk/scipy/sparse/linalg/dsolve Message-ID: <20081203201508.38FF5C7C009@scipy.org> Author: ptvirtan Date: 2008-12-03 14:14:56 -0600 (Wed, 03 Dec 2008) New Revision: 5214 Modified: trunk/scipy/sparse/linalg/dsolve/linsolve.py Log: Issue UMFPACK deprecation warning when linsolve is used, not when it is imported Modified: trunk/scipy/sparse/linalg/dsolve/linsolve.py =================================================================== --- trunk/scipy/sparse/linalg/dsolve/linsolve.py 2008-12-01 04:08:07 UTC (rev 5213) +++ trunk/scipy/sparse/linalg/dsolve/linsolve.py 2008-12-03 20:14:56 UTC (rev 5214) @@ -15,10 +15,6 @@ isUmfpack = hasattr( umfpack, 'UMFPACK_OK' ) -if isUmfpack and noScikit: - warn( 'scipy.sparse.linalg.dsolve.umfpack will be removed,' - ' install scikits.umfpack instead', DeprecationWarning ) - useUmfpack = True @@ -77,6 +73,9 @@ if isUmfpack and useUmfpack: + if noScikit: + warn( 'scipy.sparse.linalg.dsolve.umfpack will be removed,'\ + ' install scikits.umfpack instead', DeprecationWarning ) if A.dtype.char not in 'dD': raise ValueError, "convert matrix data to double, please, using"\ " .astype(), or set linsolve.useUmfpack = False" @@ -139,6 +138,10 @@ x2 = solve( rhs2 ) # Uses again the LU factors. """ if isUmfpack and useUmfpack: + if noScikit: + warn( 'scipy.sparse.linalg.dsolve.umfpack will be removed,'\ + ' install scikits.umfpack instead', DeprecationWarning ) + if not isspmatrix_csc(A): A = csc_matrix(A) warn('splu requires CSC matrix format', SparseEfficiencyWarning) From scipy-svn at scipy.org Wed Dec 3 18:24:30 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 3 Dec 2008 17:24:30 -0600 (CST) Subject: [Scipy-svn] r5215 - in trunk/doc: . source source/_static source/tutorial source/tutorial/examples Message-ID: <20081203232430.4DC3FC7C009@scipy.org> Author: ptvirtan Date: 2008-12-03 17:23:53 -0600 (Wed, 03 Dec 2008) New Revision: 5215 Removed: trunk/doc/source/tutorial/examples/10-2-1 trunk/doc/source/tutorial/examples/10-2-2 trunk/doc/source/tutorial/examples/10-2-3 trunk/doc/source/tutorial/examples/10-2-5 trunk/doc/source/tutorial/examples/10-3-1 trunk/doc/source/tutorial/examples/10-3-2 trunk/doc/source/tutorial/examples/10-3-6 trunk/doc/source/tutorial/examples/10-4-4 trunk/doc/source/tutorial/examples/2-1 trunk/doc/source/tutorial/examples/2-2 trunk/doc/source/tutorial/examples/2-3 trunk/doc/source/tutorial/examples/4-2 trunk/doc/source/tutorial/examples/4-3 trunk/doc/source/tutorial/examples/4-4 trunk/doc/source/tutorial/examples/4-5 trunk/doc/source/tutorial/examples/4-6 trunk/doc/source/tutorial/examples/5-2 trunk/doc/source/tutorial/examples/5-3 trunk/doc/source/tutorial/examples/5-4 trunk/doc/source/tutorial/examples/5-5 trunk/doc/source/tutorial/examples/5-6 trunk/doc/source/tutorial/examples/5-7 trunk/doc/source/tutorial/examples/5-8 trunk/doc/source/tutorial/examples/5-9 trunk/doc/source/tutorial/examples/6-1 trunk/doc/source/tutorial/examples/6-2 trunk/doc/source/tutorial/examples/6-3 trunk/doc/source/tutorial/examples/6-4 Modified: trunk/doc/Makefile trunk/doc/source/_static/scipy.css trunk/doc/source/conf.py trunk/doc/source/tutorial/index.rst Log: tutorial: move examples and plot codes to body, for easier editing. Make use of the new plot directive. Modified: trunk/doc/Makefile =================================================================== --- trunk/doc/Makefile 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/Makefile 2008-12-03 23:23:53 UTC (rev 5215) @@ -25,7 +25,7 @@ @echo " upload USER=... to upload results to docs.scipy.org" clean: - -rm -rf build/* source/generated + -rm -rf build/* source/generated source/_static/plot_directive upload: @test -e build/dist || { echo "make dist is required first"; exit 1; } Modified: trunk/doc/source/_static/scipy.css =================================================================== --- trunk/doc/source/_static/scipy.css 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/_static/scipy.css 2008-12-03 23:23:53 UTC (rev 5215) @@ -126,6 +126,30 @@ border: 1px solid #ee6; } +div.plot-output { + clear-after: both; +} + +div.plot-output .figure { + float: left; + text-align: center; + margin-bottom: 0; + padding-bottom: 0; +} + +div.plot-output .caption { + margin-top: 2; + padding-top: 0; +} + +div.plot-output:after { + content: ""; + display: block; + height: 0; + clear: both; +} + + /* div.admonition-example { background-color: #e4ffe4; Modified: trunk/doc/source/conf.py =================================================================== --- trunk/doc/source/conf.py 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/conf.py 2008-12-03 23:23:53 UTC (rev 5215) @@ -239,3 +239,5 @@ numpy.random.seed(123) """ plot_output_dir = '_static/plot_directive' +plot_include_source = True + Deleted: trunk/doc/source/tutorial/examples/10-2-1 =================================================================== --- trunk/doc/source/tutorial/examples/10-2-1 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/10-2-1 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,14 +0,0 @@ ->>> A = mat('[1 3 5; 2 5 1; 2 3 8]') ->>> A -matrix([[1, 3, 5], - [2, 5, 1], - [2, 3, 8]]) ->>> A.I -matrix([[-1.48, 0.36, 0.88], - [ 0.56, 0.08, -0.36], - [ 0.16, -0.12, 0.04]]) ->>> from scipy import linalg ->>> linalg.inv(A) -array([[-1.48, 0.36, 0.88], - [ 0.56, 0.08, -0.36], - [ 0.16, -0.12, 0.04]]) Deleted: trunk/doc/source/tutorial/examples/10-2-2 =================================================================== --- trunk/doc/source/tutorial/examples/10-2-2 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/10-2-2 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,10 +0,0 @@ ->>> A = mat('[1 3 5; 2 5 1; 2 3 8]') ->>> b = mat('[10;8;3]') ->>> A.I*b -matrix([[-9.28], - [ 5.16], - [ 0.76]]) ->>> linalg.solve(A,b) -array([[-9.28], - [ 5.16], - [ 0.76]]) Deleted: trunk/doc/source/tutorial/examples/10-2-3 =================================================================== --- trunk/doc/source/tutorial/examples/10-2-3 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/10-2-3 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,4 +0,0 @@ ->>> A = mat('[1 3 5; 2 5 1; 2 3 8]') ->>> linalg.det(A) --25.000000000000004 - Deleted: trunk/doc/source/tutorial/examples/10-2-5 =================================================================== --- trunk/doc/source/tutorial/examples/10-2-5 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/10-2-5 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,21 +0,0 @@ -from numpy import * -from scipy import linalg -import matplotlib.pyplot as plt - -c1,c2= 5.0,2.0 -i = r_[1:11] -xi = 0.1*i -yi = c1*exp(-xi)+c2*xi -zi = yi + 0.05*max(yi)*random.randn(len(yi)) - -A = c_[exp(-xi)[:,newaxis],xi[:,newaxis]] -c,resid,rank,sigma = linalg.lstsq(A,zi) - -xi2 = r_[0.1:1.0:100j] -yi2 = c[0]*exp(-xi2) + c[1]*xi2 - -plt.plot(xi,zi,'x',xi2,yi2) -plt.axis([0,1.1,3.0,5.5]) -plt.xlabel('$x_i$') -plt.title('Data fitting with linalg.lstsq') -plt.show() Deleted: trunk/doc/source/tutorial/examples/10-3-1 =================================================================== --- trunk/doc/source/tutorial/examples/10-3-1 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/10-3-1 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,19 +0,0 @@ ->>> from scipy import linalg ->>> A = mat('[1 5 2; 2 4 1; 3 6 2]') ->>> la,v = linalg.eig(A) ->>> l1,l2,l3 = la ->>> print l1, l2, l3 -(7.95791620491+0j) (-1.25766470568+0j) (0.299748500767+0j) - ->>> print v[:,0] -[-0.5297175 -0.44941741 -0.71932146] ->>> print v[:,1] -[-0.90730751 0.28662547 0.30763439] ->>> print v[:,2] -[ 0.28380519 -0.39012063 0.87593408] ->>> print sum(abs(v**2),axis=0) -[ 1. 1. 1.] - ->>> v1 = mat(v[:,0]).T ->>> print max(ravel(abs(A*v1-l1*v1))) -8.881784197e-16 Deleted: trunk/doc/source/tutorial/examples/10-3-2 =================================================================== --- trunk/doc/source/tutorial/examples/10-3-2 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/10-3-2 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,22 +0,0 @@ ->>> A = mat('[1 3 2; 1 2 3]') ->>> M,N = A.shape ->>> U,s,Vh = linalg.svd(A) ->>> Sig = mat(linalg.diagsvd(s,M,N)) ->>> U, Vh = mat(U), mat(Vh) ->>> print U -[[-0.70710678 -0.70710678] - [-0.70710678 0.70710678]] ->>> print Sig -[[ 5.19615242 0. 0. ] - [ 0. 1. 0. ]] ->>> print Vh -[[ -2.72165527e-01 -6.80413817e-01 -6.80413817e-01] - [ -6.18652536e-16 -7.07106781e-01 7.07106781e-01] - [ -9.62250449e-01 1.92450090e-01 1.92450090e-01]] - ->>> print A -[[1 3 2] - [1 2 3]] ->>> print U*Sig*Vh -[[ 1. 3. 2.] - [ 1. 2. 3.]] Deleted: trunk/doc/source/tutorial/examples/10-3-6 =================================================================== --- trunk/doc/source/tutorial/examples/10-3-6 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/10-3-6 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,37 +0,0 @@ ->>> from scipy import linalg ->>> A = mat('[1 3 2; 1 4 5; 2 3 6]') ->>> T,Z = linalg.schur(A) ->>> T1,Z1 = linalg.schur(A,'complex') ->>> T2,Z2 = linalg.rsf2csf(T,Z) ->>> print T -[[ 9.90012467 1.78947961 -0.65498528] - [ 0. 0.54993766 -1.57754789] - [ 0. 0.51260928 0.54993766]] ->>> print T2 -[[ 9.90012467 +0.00000000e+00j -0.32436598 +1.55463542e+00j - -0.88619748 +5.69027615e-01j] - [ 0.00000000 +0.00000000e+00j 0.54993766 +8.99258408e-01j - 1.06493862 +1.37016050e-17j] - [ 0.00000000 +0.00000000e+00j 0.00000000 +0.00000000e+00j - 0.54993766 -8.99258408e-01j]] ->>> print abs(T1-T2) # different -[[ 1.24357637e-14 2.09205364e+00 6.56028192e-01] - [ 0.00000000e+00 4.00296604e-16 1.83223097e+00] - [ 0.00000000e+00 0.00000000e+00 4.57756680e-16]] ->>> print abs(Z1-Z2) # different -[[ 0.06833781 1.10591375 0.23662249] - [ 0.11857169 0.5585604 0.29617525] - [ 0.12624999 0.75656818 0.22975038]] ->>> T,Z,T1,Z1,T2,Z2 = map(mat,(T,Z,T1,Z1,T2,Z2)) ->>> print abs(A-Z*T*Z.H) # same -[[ 1.11022302e-16 4.44089210e-16 4.44089210e-16] - [ 4.44089210e-16 1.33226763e-15 8.88178420e-16] - [ 8.88178420e-16 4.44089210e-16 2.66453526e-15]] ->>> print abs(A-Z1*T1*Z1.H) # same -[[ 1.00043248e-15 2.22301403e-15 5.55749485e-15] - [ 2.88899660e-15 8.44927041e-15 9.77322008e-15] - [ 3.11291538e-15 1.15463228e-14 1.15464861e-14]] ->>> print abs(A-Z2*T2*Z2.H) # same -[[ 3.34058710e-16 8.88611201e-16 4.18773089e-18] - [ 1.48694940e-16 8.95109973e-16 8.92966151e-16] - [ 1.33228956e-15 1.33582317e-15 3.55373104e-15]] Deleted: trunk/doc/source/tutorial/examples/10-4-4 =================================================================== --- trunk/doc/source/tutorial/examples/10-4-4 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/10-4-4 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,17 +0,0 @@ ->>> from scipy import special, random, linalg ->>> A = random.rand(3,3) ->>> B = linalg.funm(A,lambda x: special.jv(0,real(x))) ->>> print A -[[ 0.72578091 0.34105276 0.79570345] - [ 0.65767207 0.73855618 0.541453 ] - [ 0.78397086 0.68043507 0.4837898 ]] ->>> print B -[[ 0.72599893 -0.20545711 -0.22721101] - [-0.27426769 0.77255139 -0.23422637] - [-0.27612103 -0.21754832 0.7556849 ]] ->>> print linalg.eigvals(A) -[ 1.91262611+0.j 0.21846476+0.j -0.18296399+0.j] ->>> print special.jv(0, linalg.eigvals(A)) -[ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] ->>> print linalg.eigvals(B) -[ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] Deleted: trunk/doc/source/tutorial/examples/2-1 =================================================================== --- trunk/doc/source/tutorial/examples/2-1 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/2-1 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,20 +0,0 @@ ->>> mgrid[0:5,0:5] -array([[[0, 0, 0, 0, 0], - [1, 1, 1, 1, 1], - [2, 2, 2, 2, 2], - [3, 3, 3, 3, 3], - [4, 4, 4, 4, 4]], - [[0, 1, 2, 3, 4], - [0, 1, 2, 3, 4], - [0, 1, 2, 3, 4], - [0, 1, 2, 3, 4], - [0, 1, 2, 3, 4]]]) ->>> mgrid[0:5:4j,0:5:4j] -array([[[ 0. , 0. , 0. , 0. ], - [ 1.6667, 1.6667, 1.6667, 1.6667], - [ 3.3333, 3.3333, 3.3333, 3.3333], - [ 5. , 5. , 5. , 5. ]], - [[ 0. , 1.6667, 3.3333, 5. ], - [ 0. , 1.6667, 3.3333, 5. ], - [ 0. , 1.6667, 3.3333, 5. ], - [ 0. , 1.6667, 3.3333, 5. ]]]) Deleted: trunk/doc/source/tutorial/examples/2-2 =================================================================== --- trunk/doc/source/tutorial/examples/2-2 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/2-2 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,14 +0,0 @@ ->>> p = poly1d([3,4,5]) ->>> print p - 2 -3 x + 4 x + 5 ->>> print p*p - 4 3 2 -9 x + 24 x + 46 x + 40 x + 25 ->>> print p.integ(k=6) - 3 2 -x + 2 x + 5 x + 6 ->>> print p.deriv() -6 x + 4 ->>> p([4,5]) -array([ 69, 100]) \ No newline at end of file Deleted: trunk/doc/source/tutorial/examples/2-3 =================================================================== --- trunk/doc/source/tutorial/examples/2-3 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/2-3 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,6 +0,0 @@ ->>> x = r_[-2:3] ->>> x -array([-2, -1, 0, 1, 2]) ->>> select([x > 3, x >= 0],[0,x+2]) -array([0, 0, 2, 3, 4]) - Deleted: trunk/doc/source/tutorial/examples/4-2 =================================================================== --- trunk/doc/source/tutorial/examples/4-2 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/4-2 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,11 +0,0 @@ ->>> result = integrate.quad(lambda x: special.jv(2.5,x), 0, 4.5) ->>> print result -(1.1178179380783249, 7.8663172481899801e-09) - ->>> I = sqrt(2/pi)*(18.0/27*sqrt(2)*cos(4.5)-4.0/27*sqrt(2)*sin(4.5)+ - sqrt(2*pi)*special.fresnel(3/sqrt(pi))[0]) ->>> print I -1.117817938088701 - ->>> print abs(result[0]-I) -1.03761443881e-11 Deleted: trunk/doc/source/tutorial/examples/4-3 =================================================================== --- trunk/doc/source/tutorial/examples/4-3 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/4-3 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,13 +0,0 @@ ->>> from scipy.integrate import quad ->>> def integrand(t,n,x): -... return exp(-x*t) / t**n - ->>> def expint(n,x): -... return quad(integrand, 1, Inf, args=(n, x))[0] - ->>> vec_expint = vectorize(expint) - ->>> vec_expint(3,arange(1.0,4.0,0.5)) -array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049]) ->>> special.expn(3,arange(1.0,4.0,0.5)) -array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049]) Deleted: trunk/doc/source/tutorial/examples/4-4 =================================================================== --- trunk/doc/source/tutorial/examples/4-4 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/4-4 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,10 +0,0 @@ ->>> result = quad(lambda x: expint(3, x), 0, inf) ->>> print result -(0.33333333324560266, 2.8548934485373678e-09) - ->>> I3 = 1.0/3.0 ->>> print I3 -0.333333333333 - ->>> print I3 - result[0] -8.77306560731e-11 Deleted: trunk/doc/source/tutorial/examples/4-5 =================================================================== --- trunk/doc/source/tutorial/examples/4-5 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/4-5 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,10 +0,0 @@ ->>> from scipy.integrate import quad, dblquad ->>> def I(n): -... return dblquad(lambda t, x: exp(-x*t)/t**n, 0, Inf, lambda x: 1, lambda x: Inf) - ->>> print I(4) -(0.25000000000435768, 1.0518245707751597e-09) ->>> print I(3) -(0.33333333325010883, 2.8604069919261191e-09) ->>> print I(2) -(0.49999999999857514, 1.8855523253868967e-09) Deleted: trunk/doc/source/tutorial/examples/4-6 =================================================================== --- trunk/doc/source/tutorial/examples/4-6 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/4-6 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,25 +0,0 @@ ->>> from scipy.integrate import odeint ->>> from scipy.special import gamma, airy ->>> y1_0 = 1.0/3**(2.0/3.0)/gamma(2.0/3.0) ->>> y0_0 = -1.0/3**(1.0/3.0)/gamma(1.0/3.0) ->>> y0 = [y0_0, y1_0] ->>> def func(y, t): -... return [t*y[1],y[0]] - ->>> def gradient(y,t): -... return [[0,t],[1,0]] - ->>> x = arange(0,4.0, 0.01) ->>> t = x ->>> ychk = airy(x)[0] ->>> y = odeint(func, y0, t) ->>> y2 = odeint(func, y0, t, Dfun=gradient) - ->>> print ychk[:36:6] -[ 0.355028 0.339511 0.324068 0.308763 0.293658 0.278806] - ->>> print y[:36:6,1] -[ 0.355028 0.339511 0.324067 0.308763 0.293658 0.278806] - ->>> print y2[:36:6,1] -[ 0.355028 0.339511 0.324067 0.308763 0.293658 0.278806] Deleted: trunk/doc/source/tutorial/examples/5-2 =================================================================== --- trunk/doc/source/tutorial/examples/5-2 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/5-2 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,14 +0,0 @@ ->>> from scipy.optimize import fmin ->>> def rosen(x): -... """The Rosenbrock function""" -... return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0) - ->>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] ->>> xopt = fmin(rosen, x0, xtol=1e-8) -Optimization terminated successfully. - Current function value: 0.000000 - Iterations: 339 - Function evaluations: 571 - ->>> print xopt -[ 1. 1. 1. 1. 1.] Deleted: trunk/doc/source/tutorial/examples/5-3 =================================================================== --- trunk/doc/source/tutorial/examples/5-3 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/5-3 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,10 +0,0 @@ ->>> def rosen_der(x): -... xm = x[1:-1] -... xm_m1 = x[:-2] -... xm_p1 = x[2:] -... der = zeros_like(x) -... der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm) -... der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0]) -... der[-1] = 200*(x[-1]-x[-2]**2) -... return der - Deleted: trunk/doc/source/tutorial/examples/5-4 =================================================================== --- trunk/doc/source/tutorial/examples/5-4 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/5-4 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,11 +0,0 @@ ->>> from scipy.optimize import fmin_bfgs - ->>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] ->>> xopt = fmin_bfgs(rosen, x0, fprime=rosen_der) -Optimization terminated successfully. - Current function value: 0.000000 - Iterations: 53 - Function evaluations: 65 - Gradient evaluations: 65 ->>> print xopt -[ 1. 1. 1. 1. 1.] Deleted: trunk/doc/source/tutorial/examples/5-5 =================================================================== --- trunk/doc/source/tutorial/examples/5-5 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/5-5 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,21 +0,0 @@ ->>> from scipy.optimize import fmin_ncg ->>> def rosen_hess(x): -... x = asarray(x) -... H = diag(-400*x[:-1],1) - diag(400*x[:-1],-1) -... diagonal = zeros_like(x) -... diagonal[0] = 1200*x[0]-400*x[1]+2 -... diagonal[-1] = 200 -... diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:] -... H = H + diag(diagonal) -... return H - ->>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] ->>> xopt = fmin_ncg(rosen, x0, rosen_der, fhess=rosen_hess, avextol=1e-8) -Optimization terminated successfully. - Current function value: 0.000000 - Iterations: 23 - Function evaluations: 26 - Gradient evaluations: 23 - Hessian evaluations: 23 ->>> print xopt -[ 1. 1. 1. 1. 1.] Deleted: trunk/doc/source/tutorial/examples/5-6 =================================================================== --- trunk/doc/source/tutorial/examples/5-6 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/5-6 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,20 +0,0 @@ ->>> from scipy.optimize import fmin_ncg ->>> def rosen_hess_p(x,p): -... x = asarray(x) -... Hp = zeros_like(x) -... Hp[0] = (1200*x[0]**2 - 400*x[1] + 2)*p[0] - 400*x[0]*p[1] -... Hp[1:-1] = -400*x[:-2]*p[:-2]+(202+1200*x[1:-1]**2-400*x[2:])*p[1:-1] \ -... -400*x[1:-1]*p[2:] -... Hp[-1] = -400*x[-2]*p[-2] + 200*p[-1] -... return Hp - ->>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] ->>> xopt = fmin_ncg(rosen, x0, rosen_der, fhess_p=rosen_hess_p, avextol=1e-8) -Optimization terminated successfully. - Current function value: 0.000000 - Iterations: 22 - Function evaluations: 25 - Gradient evaluations: 22 - Hessian evaluations: 54 ->>> print xopt -[ 1. 1. 1. 1. 1.] Deleted: trunk/doc/source/tutorial/examples/5-7 =================================================================== --- trunk/doc/source/tutorial/examples/5-7 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/5-7 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,31 +0,0 @@ ->>> from numpy import * ->>> x = arange(0,6e-2,6e-2/30) ->>> A,k,theta = 10, 1.0/3e-2, pi/6 ->>> y_true = A*sin(2*pi*k*x+theta) ->>> y_meas = y_true + 2*random.randn(len(x)) - ->>> def residuals(p, y, x): -... A,k,theta = p -... err = y-A*sin(2*pi*k*x+theta) -... return err - ->>> def peval(x, p): -... return p[0]*sin(2*pi*p[1]*x+p[2]) - ->>> p0 = [8, 1/2.3e-2, pi/3] ->>> print array(p0) -[ 8. 43.4783 1.0472] - ->>> from scipy.optimize import leastsq ->>> plsq = leastsq(residuals, p0, args=(y_meas, x)) ->>> print plsq[0] -[ 10.9437 33.3605 0.5834] - ->>> print array([A, k, theta]) -[ 10. 33.3333 0.5236] - ->>> import matplotlib.pyplot as plt ->>> plt.plot(x,peval(x,plsq[0]),x,y_meas,'o',x,y_true) ->>> plt.title('Least-squares fit to noisy data') ->>> plt.legend(['Fit', 'Noisy', 'True']) ->>> plt.show() Deleted: trunk/doc/source/tutorial/examples/5-8 =================================================================== --- trunk/doc/source/tutorial/examples/5-8 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/5-8 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,7 +0,0 @@ ->>> from scipy.special import j1 - ->>> from scipy.optimize import fminbound ->>> xmin = fminbound(j1, 4, 7) ->>> print xmin -5.33144184241 - Deleted: trunk/doc/source/tutorial/examples/5-9 =================================================================== --- trunk/doc/source/tutorial/examples/5-9 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/5-9 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,16 +0,0 @@ ->>> def func(x): - return x + 2*cos(x) - ->>> def func2(x): - out = [x[0]*cos(x[1]) - 4] - out.append(x[1]*x[0] - x[1] - 5) - return out - ->>> from scipy.optimize import fsolve ->>> x0 = fsolve(func, 0.3) ->>> print x0 --1.02986652932 - ->>> x02 = fsolve(func2, [1, 1]) ->>> print x02 -[ 6.50409711 0.90841421] Deleted: trunk/doc/source/tutorial/examples/6-1 =================================================================== --- trunk/doc/source/tutorial/examples/6-1 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/6-1 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,10 +0,0 @@ ->>> from numpy import * ->>> from scipy import interpolate - ->>> x = arange(0,10) ->>> y = exp(-x/3.0) ->>> f = interpolate.interp1d(x, y) - ->>> xnew = arange(0,9,0.1) ->>> import matplotlib.pyplot as plt ->>> plt.plot(x,y,'o',xnew,f(xnew),'-') Deleted: trunk/doc/source/tutorial/examples/6-2 =================================================================== --- trunk/doc/source/tutorial/examples/6-2 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/6-2 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,61 +0,0 @@ ->>> from numpy import * ->>> import matplotlib.pyplot as plt ->>> from scipy import interpolate - ->>> # Cubic-spline ->>> x = arange(0,2*pi+pi/4,2*pi/8) ->>> y = sin(x) ->>> tck = interpolate.splrep(x,y,s=0) ->>> xnew = arange(0,2*pi,pi/50) ->>> ynew = interpolate.splev(xnew,tck,der=0) - ->>> plt.figure() ->>> plt.plot(x,y,'x',xnew,ynew,xnew,sin(xnew),x,y,'b') ->>> plt.legend(['Linear','Cubic Spline', 'True']) ->>> plt.axis([-0.05,6.33,-1.05,1.05]) ->>> plt.title('Cubic-spline interpolation') ->>> plt.show() - ->>> # Derivative of spline ->>> yder = interpolate.splev(xnew,tck,der=1) ->>> plt.figure() ->>> plt.plot(xnew,yder,xnew,cos(xnew),'--') ->>> plt.legend(['Cubic Spline', 'True']) ->>> plt.axis([-0.05,6.33,-1.05,1.05]) ->>> plt.title('Derivative estimation from spline') ->>> plt.show() - ->>> # Integral of spline ->>> def integ(x,tck,constant=-1): ->>> x = atleast_1d(x) ->>> out = zeros(x.shape, dtype=x.dtype) ->>> for n in xrange(len(out)): ->>> out[n] = interpolate.splint(0,x[n],tck) ->>> out += constant ->>> return out ->>> ->>> yint = integ(xnew,tck) ->>> plt.figure() ->>> plt.plot(xnew,yint,xnew,-cos(xnew),'--') ->>> plt.legend(['Cubic Spline', 'True']) ->>> plt.axis([-0.05,6.33,-1.05,1.05]) ->>> plt.title('Integral estimation from spline') ->>> plt.show() - ->>> # Roots of spline ->>> print interpolate.sproot(tck) -[ 0. 3.1416] - ->>> # Parametric spline ->>> t = arange(0,1.1,.1) ->>> x = sin(2*pi*t) ->>> y = cos(2*pi*t) ->>> tck,u = interpolate.splprep([x,y],s=0) ->>> unew = arange(0,1.01,0.01) ->>> out = interpolate.splev(unew,tck) ->>> plt.figure() ->>> plt.plot(x,y,'x',out[0],out[1],sin(2*pi*unew),cos(2*pi*unew),x,y,'b') ->>> plt.legend(['Linear','Cubic Spline', 'True']) ->>> plt.axis([-1.05,1.05,-1.05,1.05]) ->>> plt.title('Spline of parametrically-defined curve') ->>> plt.show() Deleted: trunk/doc/source/tutorial/examples/6-3 =================================================================== --- trunk/doc/source/tutorial/examples/6-3 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/6-3 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,24 +0,0 @@ ->>> from numpy import * ->>> from scipy import interpolate ->>> import matplotlib.pyplot as plt - ->>> # Define function over sparse 20x20 grid ->>> x,y = mgrid[-1:1:20j,-1:1:20j] ->>> z = (x+y)*exp(-6.0*(x*x+y*y)) - ->>> plt.figure() ->>> plt.pcolor(x,y,z) ->>> plt.colorbar() ->>> plt.title("Sparsely sampled function.") ->>> plt.show() - ->>> # Interpolate function over new 70x70 grid ->>> xnew,ynew = mgrid[-1:1:70j,-1:1:70j] ->>> tck = interpolate.bisplrep(x,y,z,s=0) ->>> znew = interpolate.bisplev(xnew[:,0],ynew[0,:],tck) - ->>> plt.figure() ->>> plt.pcolor(xnew,ynew,znew) ->>> plt.colorbar() ->>> plt.title("Interpolated function.") ->>> plt.show() Deleted: trunk/doc/source/tutorial/examples/6-4 =================================================================== --- trunk/doc/source/tutorial/examples/6-4 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/examples/6-4 2008-12-03 23:23:53 UTC (rev 5215) @@ -1,25 +0,0 @@ ->>> from numpy import * ->>> from scipy import signal, misc ->>> import matplotlib.pyplot as plt - ->>> image = misc.lena().astype(float32) ->>> derfilt = array([1.0,-2,1.0],float32) ->>> ck = signal.cspline2d(image,8.0) ->>> deriv = signal.sepfir2d(ck, derfilt, [1]) + \ ->>> signal.sepfir2d(ck, [1], derfilt) ->>> ->>> ## Alternatively we could have done: ->>> ## laplacian = array([[0,1,0],[1,-4,1],[0,1,0]],float32) ->>> ## deriv2 = signal.convolve2d(ck,laplacian,mode='same',boundary='symm') - ->>> plt.figure() ->>> plt.imshow(image) ->>> plt.gray() ->>> plt.title('Original image') ->>> plt.show() - ->>> plt.figure() ->>> plt.imshow(deriv) ->>> plt.gray() ->>> plt.title('Output of spline edge filter') ->>> plt.show() Modified: trunk/doc/source/tutorial/index.rst =================================================================== --- trunk/doc/source/tutorial/index.rst 2008-12-03 20:14:56 UTC (rev 5214) +++ trunk/doc/source/tutorial/index.rst 2008-12-03 23:23:53 UTC (rev 5215) @@ -267,7 +267,26 @@ volume. The easiest way to understand this is with an example of its usage: -.. literalinclude:: examples/2-1 + >>> mgrid[0:5,0:5] + array([[[0, 0, 0, 0, 0], + [1, 1, 1, 1, 1], + [2, 2, 2, 2, 2], + [3, 3, 3, 3, 3], + [4, 4, 4, 4, 4]], + [[0, 1, 2, 3, 4], + [0, 1, 2, 3, 4], + [0, 1, 2, 3, 4], + [0, 1, 2, 3, 4], + [0, 1, 2, 3, 4]]]) + >>> mgrid[0:5:4j,0:5:4j] + array([[[ 0. , 0. , 0. , 0. ], + [ 1.6667, 1.6667, 1.6667, 1.6667], + [ 3.3333, 3.3333, 3.3333, 3.3333], + [ 5. , 5. , 5. , 5. ]], + [[ 0. , 1.6667, 3.3333, 5. ], + [ 0. , 1.6667, 3.3333, 5. ], + [ 0. , 1.6667, 3.3333, 5. ], + [ 0. , 1.6667, 3.3333, 5. ]]]) Having meshed arrays like this is sometimes very useful. However, it is not always needed just to evaluate some N-dimensional function over @@ -309,7 +328,20 @@ expressions, integrated, differentiated, and evaluated. It even prints like a polynomial: -.. literalinclude:: examples/2-2 + >>> p = poly1d([3,4,5]) + >>> print p + 2 + 3 x + 4 x + 5 + >>> print p*p + 4 3 2 + 9 x + 24 x + 46 x + 40 x + 25 + >>> print p.integ(k=6) + 3 2 + x + 2 x + 5 x + 6 + >>> print p.deriv() + 6 x + 4 + >>> p([4,5]) + array([ 69, 100]) The other way to handle polynomials is as an array of coefficients with the first element of the array giving the coefficient of the @@ -378,7 +410,11 @@ the array in a ``choicelist`` corresponding to the first condition in ``condlist`` that is true. For example -.. literalinclude:: examples/2-3 + >>> x = r_[-2:3] + >>> x + array([-2, -1, 0, 1, 2]) + >>> select([x > 3, x >= 0],[0,x+2]) + array([0, 0, 2, 3, 4]) Common functions @@ -458,7 +494,17 @@ This could be computed using :obj:`quad`: -.. literalinclude:: examples/4-2 + >>> result = integrate.quad(lambda x: special.jv(2.5,x), 0, 4.5) + >>> print result + (1.1178179380783249, 7.8663172481899801e-09) + + >>> I = sqrt(2/pi)*(18.0/27*sqrt(2)*cos(4.5)-4.0/27*sqrt(2)*sin(4.5)+ + sqrt(2*pi)*special.fresnel(3/sqrt(pi))[0]) + >>> print I + 1.117817938088701 + + >>> print abs(result[0]-I) + 1.03761443881e-11 The first argument to quad is a "callable "Python object ( *i.e* a function, method, or class instance). Notice the use of a lambda- function in this case as the argument. The next two arguments are the @@ -496,7 +542,19 @@ :obj:`special.expn` can be replicated by defining a new function :obj:`vec_expint` based on the routine :obj:`quad`: -.. literalinclude:: examples/4-3 + >>> from scipy.integrate import quad + >>> def integrand(t,n,x): + ... return exp(-x*t) / t**n + + >>> def expint(n,x): + ... return quad(integrand, 1, Inf, args=(n, x))[0] + + >>> vec_expint = vectorize(expint) + + >>> vec_expint(3,arange(1.0,4.0,0.5)) + array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049]) + >>> special.expn(3,arange(1.0,4.0,0.5)) + array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049]) The function which is integrated can even use the quad argument (though the error bound may underestimate the error due to possible @@ -507,8 +565,17 @@ \[ I_{n}=\int_{0}^{\infty}\int_{1}^{\infty}\frac{e^{-xt}}{t^{n}}\, dt\, dx=\frac{1}{n}.\] -.. literalinclude:: examples/4-4 - + >>> result = quad(lambda x: expint(3, x), 0, inf) + >>> print result + (0.33333333324560266, 2.8548934485373678e-09) + + >>> I3 = 1.0/3.0 + >>> print I3 + 0.333333333333 + + >>> print I3 - result[0] + 8.77306560731e-11 + This last example shows that multiple integration can be handled using repeated calls to :func:`quad`. The mechanics of this for double and triple integration have been wrapped up into the functions @@ -519,7 +586,16 @@ functions. An example of using double integration to compute several values of :math:`I_{n}` is shown below: -.. literalinclude:: examples/4-5 + >>> from scipy.integrate import quad, dblquad + >>> def I(n): + ... return dblquad(lambda t, x: exp(-x*t)/t**n, 0, Inf, lambda x: 1, lambda x: Inf) + + >>> print I(4) + (0.25000000000435768, 1.0518245707751597e-09) + >>> print I(3) + (0.33333333325010883, 2.8604069919261191e-09) + >>> print I(2) + (0.49999999999857514, 1.8855523253868967e-09) Gaussian quadrature (integrate.gauss_quadtol) @@ -633,7 +709,31 @@ (with respect to :math:`\mathbf{y}` ) of the function, :math:`\mathbf{f}\left(\mathbf{y},t\right)`. -.. literalinclude:: examples/4-6 + >>> from scipy.integrate import odeint + >>> from scipy.special import gamma, airy + >>> y1_0 = 1.0/3**(2.0/3.0)/gamma(2.0/3.0) + >>> y0_0 = -1.0/3**(1.0/3.0)/gamma(1.0/3.0) + >>> y0 = [y0_0, y1_0] + >>> def func(y, t): + ... return [t*y[1],y[0]] + + >>> def gradient(y,t): + ... return [[0,t],[1,0]] + + >>> x = arange(0,4.0, 0.01) + >>> t = x + >>> ychk = airy(x)[0] + >>> y = odeint(func, y0, t) + >>> y2 = odeint(func, y0, t, Dfun=gradient) + + >>> print ychk[:36:6] + [ 0.355028 0.339511 0.324068 0.308763 0.293658 0.278806] + + >>> print y[:36:6,1] + [ 0.355028 0.339511 0.324067 0.308763 0.293658 0.278806] + + >>> print y2[:36:6,1] + [ 0.355028 0.339511 0.324067 0.308763 0.293658 0.278806] Optimization (optimize) @@ -673,7 +773,20 @@ The minimum value of this function is 0 which is achieved when :math:`x_{i}=1.` This minimum can be found using the :obj:`fmin` routine as shown in the example below: -.. literalinclude:: examples/5-2 + >>> from scipy.optimize import fmin + >>> def rosen(x): + ... """The Rosenbrock function""" + ... return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0) + + >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] + >>> xopt = fmin(rosen, x0, xtol=1e-8) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 339 + Function evaluations: 571 + + >>> print xopt + [ 1. 1. 1. 1. 1.] Another optimization algorithm that needs only function calls to find the minimum is Powell's method available as :func:`optimize.fmin_powell`. @@ -708,14 +821,32 @@ A Python function which computes this gradient is constructed by the code-segment: -.. literalinclude:: examples/5-3 - + >>> def rosen_der(x): + ... xm = x[1:-1] + ... xm_m1 = x[:-2] + ... xm_p1 = x[2:] + ... der = zeros_like(x) + ... der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm) + ... der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0]) + ... der[-1] = 200*(x[-1]-x[-2]**2) + ... return der + The calling signature for the BFGS minimization algorithm is similar to :obj:`fmin` with the addition of the *fprime* argument. An example usage of :obj:`fmin_bfgs` is shown in the following example which minimizes the Rosenbrock function. -.. literalinclude:: examples/5-4 + >>> from scipy.optimize import fmin_bfgs + + >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] + >>> xopt = fmin_bfgs(rosen, x0, fprime=rosen_der) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 53 + Function evaluations: 65 + Gradient evaluations: 65 + >>> print xopt + [ 1. 1. 1. 1. 1.] Newton-Conjugate-Gradient (optimize.fmin_ncg) @@ -781,10 +912,29 @@ The code which computes this Hessian along with the code to minimize the function using :obj:`fmin_ncg` is shown in the following example: -.. literalinclude:: examples/5-5 + >>> from scipy.optimize import fmin_ncg + >>> def rosen_hess(x): + ... x = asarray(x) + ... H = diag(-400*x[:-1],1) - diag(400*x[:-1],-1) + ... diagonal = zeros_like(x) + ... diagonal[0] = 1200*x[0]-400*x[1]+2 + ... diagonal[-1] = 200 + ... diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:] + ... H = H + diag(diagonal) + ... return H + + >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] + >>> xopt = fmin_ncg(rosen, x0, rosen_der, fhess=rosen_hess, avextol=1e-8) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 23 + Function evaluations: 26 + Gradient evaluations: 23 + Hessian evaluations: 23 + >>> print xopt + [ 1. 1. 1. 1. 1.] - Hessian product example: ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -811,7 +961,26 @@ Code which makes use of the *fhess_p* keyword to minimize the Rosenbrock function using :obj:`fmin_ncg` follows: -.. literalinclude:: examples/5-6 + >>> from scipy.optimize import fmin_ncg + >>> def rosen_hess_p(x,p): + ... x = asarray(x) + ... Hp = zeros_like(x) + ... Hp[0] = (1200*x[0]**2 - 400*x[1] + 2)*p[0] - 400*x[0]*p[1] + ... Hp[1:-1] = -400*x[:-2]*p[:-2]+(202+1200*x[1:-1]**2-400*x[2:])*p[1:-1] \ + ... -400*x[1:-1]*p[2:] + ... Hp[-1] = -400*x[-2]*p[-2] + 200*p[-1] + ... return Hp + + >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] + >>> xopt = fmin_ncg(rosen, x0, rosen_der, fhess_p=rosen_hess_p, avextol=1e-8) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 22 + Function evaluations: 25 + Gradient evaluations: 22 + Hessian evaluations: 54 + >>> print xopt + [ 1. 1. 1. 1. 1.] Least-square fitting (minimize.leastsq) @@ -862,20 +1031,47 @@ By defining a function to compute the residuals and (selecting an appropriate starting position), the least-squares fit routine can be -used to find the best-fit parameters :math:`\hat{A},\,\hat{k},\,\hat{\theta}` . This is shown in the following example and a plot of the results is -shown in Figure `1 <#fig-least-squares-fit>`__ . +used to find the best-fit parameters :math:`\hat{A},\,\hat{k},\,\hat{\theta}`. +This is shown in the following example: -.. _`fig:least_squares_fit`: +.. plot:: -.. plot:: source/tutorial/examples/5-7 - :include-source: - :doctest-format: - :align: center + >>> from numpy import * + >>> x = arange(0,6e-2,6e-2/30) + >>> A,k,theta = 10, 1.0/3e-2, pi/6 + >>> y_true = A*sin(2*pi*k*x+theta) + >>> y_meas = y_true + 2*random.randn(len(x)) -.. XXX: **Figure 1** Least-square fitting to noisy data using -.. XXX: :obj:`scipy.optimize.leastsq` + >>> def residuals(p, y, x): + ... A,k,theta = p + ... err = y-A*sin(2*pi*k*x+theta) + ... return err + >>> def peval(x, p): + ... return p[0]*sin(2*pi*p[1]*x+p[2]) + >>> p0 = [8, 1/2.3e-2, pi/3] + >>> print array(p0) + [ 8. 43.4783 1.0472] + + >>> from scipy.optimize import leastsq + >>> plsq = leastsq(residuals, p0, args=(y_meas, x)) + >>> print plsq[0] + [ 10.9437 33.3605 0.5834] + + >>> print array([A, k, theta]) + [ 10. 33.3333 0.5236] + + >>> import matplotlib.pyplot as plt + >>> plt.plot(x,peval(x,plsq[0]),x,y_meas,'o',x,y_true) + >>> plt.title('Least-squares fit to noisy data') + >>> plt.legend(['Fit', 'Noisy', 'True']) + >>> plt.show() + +.. :caption: Least-square fitting to noisy data using +.. :obj:`scipy.optimize.leastsq` + + Scalar function minimizers -------------------------- @@ -915,11 +1111,13 @@ For example, to find the minimum of :math:`J_{1}\left(x\right)` near :math:`x=5` , :obj:`fminbound` can be called using the interval :math:`\left[4,7\right]` as a constraint. The result is :math:`x_{\textrm{min}}=5.3314` : + >>> from scipy.special import j1 + >>> from scipy.optimize import fminbound + >>> xmin = fminbound(j1, 4, 7) + >>> print xmin + 5.33144184241 -.. literalinclude:: examples/5-8 - - Root finding ------------ @@ -945,11 +1143,25 @@ The results are :math:`x=-1.0299` and :math:`x_{0}=6.5041,\, x_{1}=0.9084` . + >>> def func(x): + ... return x + 2*cos(x) + + >>> def func2(x): + ... out = [x[0]*cos(x[1]) - 4] + ... out.append(x[1]*x[0] - x[1] - 5) + ... return out + + >>> from scipy.optimize import fsolve + >>> x0 = fsolve(func, 0.3) + >>> print x0 + -1.02986652932 + + >>> x02 = fsolve(func2, [1, 1]) + >>> print x02 + [ 6.50409711 0.90841421] + -.. literalinclude:: examples/5-9 - - Scalar function root finding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -994,17 +1206,23 @@ specified at instantiation time. The following example demonstrates it's use. -.. _`fig:inter_1d`: +.. plot:: -.. plot:: source/tutorial/examples/6-1 - :doctest-format: - :include-source: - :align: center + >>> from numpy import * + >>> from scipy import interpolate -.. **Figure 2** One-dimensional interpolation using the - class :obj:`interpolate.interp1d` + >>> x = arange(0,10) + >>> y = exp(-x/3.0) + >>> f = interpolate.interp1d(x, y) + >>> xnew = arange(0,9,0.1) + >>> import matplotlib.pyplot as plt + >>> plt.plot(x,y,'o',xnew,f(xnew),'-') +.. :caption: One-dimensional interpolation using the +.. class :obj:`interpolate.interp1d` + + Spline interpolation in 1-d (interpolate.splXXX) ------------------------------------------------ @@ -1014,17 +1232,32 @@ representation, there are two different was to represent a curve and obtain (smoothing) spline coefficients: directly and parametrically. The direct method finds the spline representation of a curve in a two- -dimensional plane using the function :obj:`interpolate.splrep`. The first two arguments are the only ones required, and these provide -the :math:`x` and :math:`y` components of the curve. The normal output is a 3-tuple, :math:`\left(t,c,k\right)` , containing the knot-points, :math:`t` , the coefficients :math:`c` and the order :math:`k` of the spline. The default spline order is cubic, but this can be -changed with the input keyword, *k.* +dimensional plane using the function :obj:`interpolate.splrep`. The +first two arguments are the only ones required, and these provide the +:math:`x` and :math:`y` components of the curve. The normal output is +a 3-tuple, :math:`\left(t,c,k\right)` , containing the knot-points, +:math:`t` , the coefficients :math:`c` and the order :math:`k` of the +spline. The default spline order is cubic, but this can be changed +with the input keyword, *k.* -For curves in :math:`N` -dimensional space the function :obj:`interpolate.splprep` allows defining the curve parametrically. For this function only 1 -input argument is required. This input is a list of :math:`N` -arrays representing the curve in :math:`N` -dimensional space. The length of each array is the number of curve -points, and each array provides one component of the :math:`N` -dimensional data point. The parameter variable is given with the -keword argument, *u,* which defaults to an equally-spaced monotonic sequence between :math:`0` and :math:`1` . The default output consists of two objects: a 3-tuple, :math:`\left(t,c,k\right)` , containing the spline representation and the parameter variable :math:`u.` +For curves in :math:`N` -dimensional space the function +:obj:`interpolate.splprep` allows defining the curve +parametrically. For this function only 1 input argument is +required. This input is a list of :math:`N` -arrays representing the +curve in :math:`N` -dimensional space. The length of each array is the +number of curve points, and each array provides one component of the +:math:`N` -dimensional data point. The parameter variable is given +with the keword argument, *u,* which defaults to an equally-spaced +monotonic sequence between :math:`0` and :math:`1` . The default +output consists of two objects: a 3-tuple, :math:`\left(t,c,k\right)` +, containing the spline representation and the parameter variable +:math:`u.` -The keyword argument, *s* , is used to specify the amount of smoothing to perform during the -spline fit. The default value of :math:`s` is :math:`s=m-\sqrt{2m}` where :math:`m` is the number of data-points being fit. Therefore, **if no smoothing is desired a value of** :math:`\mathbf{s}=0` **should be passed to the routines.** +The keyword argument, *s* , is used to specify the amount of smoothing +to perform during the spline fit. The default value of :math:`s` is +:math:`s=m-\sqrt{2m}` where :math:`m` is the number of data-points +being fit. Therefore, **if no smoothing is desired a value of** +:math:`\mathbf{s}=0` **should be passed to the routines.** Once the spline representation of the data has been determined, functions are available for evaluating the spline @@ -1034,14 +1267,78 @@ :func:`interpolate.splint`). In addition, for cubic splines ( :math:`k=3` ) with 8 or more knots, the roots of the spline can be estimated ( :func:`interpolate.sproot`). These functions are demonstrated in the -example that follows (see also Figure `3 <#fig-spline-1d>`__ ). +example that follows. -.. plot:: source/tutorial/examples/6-2 - :include-source: - :doctest-format: - :align: center +.. plot:: + >>> from numpy import * + >>> import matplotlib.pyplot as plt + >>> from scipy import interpolate + Cubic-spline + + >>> x = arange(0,2*pi+pi/4,2*pi/8) + >>> y = sin(x) + >>> tck = interpolate.splrep(x,y,s=0) + >>> xnew = arange(0,2*pi,pi/50) + >>> ynew = interpolate.splev(xnew,tck,der=0) + + >>> plt.figure() + >>> plt.plot(x,y,'x',xnew,ynew,xnew,sin(xnew),x,y,'b') + >>> plt.legend(['Linear','Cubic Spline', 'True']) + >>> plt.axis([-0.05,6.33,-1.05,1.05]) + >>> plt.title('Cubic-spline interpolation') + >>> plt.show() + + Derivative of spline + + >>> yder = interpolate.splev(xnew,tck,der=1) + >>> plt.figure() + >>> plt.plot(xnew,yder,xnew,cos(xnew),'--') + >>> plt.legend(['Cubic Spline', 'True']) + >>> plt.axis([-0.05,6.33,-1.05,1.05]) + >>> plt.title('Derivative estimation from spline') + >>> plt.show() + + Integral of spline + + >>> def integ(x,tck,constant=-1): + >>> x = atleast_1d(x) + >>> out = zeros(x.shape, dtype=x.dtype) + >>> for n in xrange(len(out)): + >>> out[n] = interpolate.splint(0,x[n],tck) + >>> out += constant + >>> return out + >>> + >>> yint = integ(xnew,tck) + >>> plt.figure() + >>> plt.plot(xnew,yint,xnew,-cos(xnew),'--') + >>> plt.legend(['Cubic Spline', 'True']) + >>> plt.axis([-0.05,6.33,-1.05,1.05]) + >>> plt.title('Integral estimation from spline') + >>> plt.show() + + Roots of spline + + >>> print interpolate.sproot(tck) + [ 0. 3.1416] + + Parametric spline + + >>> t = arange(0,1.1,.1) + >>> x = sin(2*pi*t) + >>> y = cos(2*pi*t) + >>> tck,u = interpolate.splprep([x,y],s=0) + >>> unew = arange(0,1.01,0.01) + >>> out = interpolate.splev(unew,tck) + >>> plt.figure() + >>> plt.plot(x,y,'x',out[0],out[1],sin(2*pi*unew),cos(2*pi*unew),x,y,'b') + >>> plt.legend(['Linear','Cubic Spline', 'True']) + >>> plt.axis([-1.05,1.05,-1.05,1.05]) + >>> plt.title('Spline of parametrically-defined curve') + >>> plt.show() + + Two-dimensional spline representation (interpolate.bisplrep) ------------------------------------------------------------ @@ -1083,15 +1380,38 @@ .. _`fig:2d_interp`: -.. plot:: source/tutorial/examples/6-3 - :doctest-format: - :include-source: - :align: center +.. plot:: -.. XXX: **Figure 4** -.. XXX: Example of two-dimensional spline interpolation. + >>> from numpy import * + >>> from scipy import interpolate + >>> import matplotlib.pyplot as plt + Define function over sparse 20x20 grid + >>> x,y = mgrid[-1:1:20j,-1:1:20j] + >>> z = (x+y)*exp(-6.0*(x*x+y*y)) + + >>> plt.figure() + >>> plt.pcolor(x,y,z) + >>> plt.colorbar() + >>> plt.title("Sparsely sampled function.") + >>> plt.show() + + Interpolate function over new 70x70 grid + + >>> xnew,ynew = mgrid[-1:1:70j,-1:1:70j] + >>> tck = interpolate.bisplrep(x,y,z,s=0) + >>> znew = interpolate.bisplev(xnew[:,0],ynew[0,:],tck) + + >>> plt.figure() + >>> plt.pcolor(xnew,ynew,znew) + >>> plt.colorbar() + >>> plt.title("Interpolated function.") + >>> plt.show() + +.. :caption: Example of two-dimensional spline interpolation. + + Signal Processing (signal) ========================== @@ -1210,16 +1530,38 @@ .. _`fig:lena_edge_spline`: -.. plot:: source/tutorial/examples/6-4 - :doctest-format: - :include-source: - :align: center +.. plot:: -.. **Figure 5** -.. .. image: figs/lena_edge.pdf -.. Example of using smoothing splines to filter images. + >>> from numpy import * + >>> from scipy import signal, misc + >>> import matplotlib.pyplot as plt + >>> image = misc.lena().astype(float32) + >>> derfilt = array([1.0,-2,1.0],float32) + >>> ck = signal.cspline2d(image,8.0) + >>> deriv = signal.sepfir2d(ck, derfilt, [1]) + \ + >>> signal.sepfir2d(ck, [1], derfilt) + Alternatively we could have done:: + + laplacian = array([[0,1,0],[1,-4,1],[0,1,0]],float32) + deriv2 = signal.convolve2d(ck,laplacian,mode='same',boundary='symm') + + >>> plt.figure() + >>> plt.imshow(image) + >>> plt.gray() + >>> plt.title('Original image') + >>> plt.show() + + >>> plt.figure() + >>> plt.imshow(deriv) + >>> plt.gray() + >>> plt.title('Output of spline edge filter') + >>> plt.show() + +.. :caption: Example of using smoothing splines to filter images. + + Filtering --------- @@ -1613,8 +1955,21 @@ The following example demonstrates this computation in SciPy -.. literalinclude:: examples/10-2-1 - + >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') + >>> A + matrix([[1, 3, 5], + [2, 5, 1], + [2, 3, 8]]) + >>> A.I + matrix([[-1.48, 0.36, 0.88], + [ 0.56, 0.08, -0.36], + [ 0.16, -0.12, 0.04]]) + >>> from scipy import linalg + >>> linalg.inv(A) + array([[-1.48, 0.36, 0.88], + [ 0.56, 0.08, -0.36], + [ 0.16, -0.12, 0.04]]) + Solving linear system ^^^^^^^^^^^^^^^^^^^^^ @@ -1641,8 +1996,18 @@ faster and more numerically stable. In this case it however gives the same answer as shown in the following example: -.. literalinclude:: examples/10-2-2 + >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') + >>> b = mat('[10;8;3]') + >>> A.I*b + matrix([[-9.28], + [ 5.16], + [ 0.76]]) + >>> linalg.solve(A,b) + array([[-9.28], + [ 5.16], + [ 0.76]]) + Finding Determinant ^^^^^^^^^^^^^^^^^^^ @@ -1671,8 +2036,11 @@ In SciPy this is computed as shown in this example: -.. literalinclude:: examples/10-2-3 + >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') + >>> linalg.det(A) + -25.000000000000004 + Computing norms ^^^^^^^^^^^^^^^ @@ -1773,11 +2141,32 @@ where :math:`x_{i}=0.1i` for :math:`i=1\ldots10` , :math:`c_{1}=5` , and :math:`c_{2}=4.` Noise is added to :math:`y_{i}` and the coefficients :math:`c_{1}` and :math:`c_{2}` are estimated using linear least squares. -.. plot:: source/tutorial/examples/10-2-5 - :include-source: - :align: center +.. plot:: + >>> from numpy import * + >>> from scipy import linalg + >>> import matplotlib.pyplot as plt + >>> c1,c2= 5.0,2.0 + >>> i = r_[1:11] + >>> xi = 0.1*i + >>> yi = c1*exp(-xi)+c2*xi + >>> zi = yi + 0.05*max(yi)*random.randn(len(yi)) + + >>> A = c_[exp(-xi)[:,newaxis],xi[:,newaxis]] + >>> c,resid,rank,sigma = linalg.lstsq(A,zi) + + >>> xi2 = r_[0.1:1.0:100j] + >>> yi2 = c[0]*exp(-xi2) + c[1]*xi2 + + >>> plt.plot(xi,zi,'x',xi2,yi2) + >>> plt.axis([0,1.1,3.0,5.5]) + >>> plt.xlabel('$x_i$') + >>> plt.title('Data fitting with linalg.lstsq') + >>> plt.show() + +.. :caption: Example of linear least-squares fit + Generalized inverse ^^^^^^^^^^^^^^^^^^^ @@ -1901,8 +2290,27 @@ the original equation. The eigenvectors associated with these eigenvalues can then be found. -.. literalinclude:: examples/10-3-1 + >>> from scipy import linalg + >>> A = mat('[1 5 2; 2 4 1; 3 6 2]') + >>> la,v = linalg.eig(A) + >>> l1,l2,l3 = la + >>> print l1, l2, l3 + (7.95791620491+0j) (-1.25766470568+0j) (0.299748500767+0j) + + >>> print v[:,0] + [-0.5297175 -0.44941741 -0.71932146] + >>> print v[:,1] + [-0.90730751 0.28662547 0.30763439] + >>> print v[:,2] + [ 0.28380519 -0.39012063 0.87593408] + >>> print sum(abs(v**2),axis=0) + [ 1. 1. 1.] + + >>> v1 = mat(v[:,0]).T + >>> print max(ravel(abs(A*v1-l1*v1))) + 8.881784197e-16 + Singular value decomposition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1918,7 +2326,28 @@ is the singular-value decomposition of :math:`\mathbf{A}.` Every matrix has a singular value decomposition. Sometimes, the singular values are called the spectrum of :math:`\mathbf{A}.` The command :obj:`linalg.svd` will return :math:`\mathbf{U}` , :math:`\mathbf{V}^{H}` , and :math:`\sigma_{i}` as an array of the singular values. To obtain the matrix :math:`\mathbf{\Sigma}` use :obj:`linalg.diagsvd`. The following example illustrates the use of :obj:`linalg.svd` . -.. literalinclude:: examples/10-3-2 + >>> A = mat('[1 3 2; 1 2 3]') + >>> M,N = A.shape + >>> U,s,Vh = linalg.svd(A) + >>> Sig = mat(linalg.diagsvd(s,M,N)) + >>> U, Vh = mat(U), mat(Vh) + >>> print U + [[-0.70710678 -0.70710678] + [-0.70710678 0.70710678]] + >>> print Sig + [[ 5.19615242 0. 0. ] + [ 0. 1. 0. ]] + >>> print Vh + [[ -2.72165527e-01 -6.80413817e-01 -6.80413817e-01] + [ -6.18652536e-16 -7.07106781e-01 7.07106781e-01] + [ -9.62250449e-01 1.92450090e-01 1.92450090e-01]] + + >>> print A + [[1 3 2] + [1 2 3]] + >>> print U*Sig*Vh + [[ 1. 3. 2.] + [ 1. 2. 3.]] .. [#] A hermition matrix :math:`\mathbf{D}` satisfies :math:`\mathbf{D}^{H}=\mathbf{D}.` @@ -2016,7 +2445,43 @@ The following example illustrates the schur decomposition: -.. literalinclude:: examples/10-3-6 + >>> from scipy import linalg + >>> A = mat('[1 3 2; 1 4 5; 2 3 6]') + >>> T,Z = linalg.schur(A) + >>> T1,Z1 = linalg.schur(A,'complex') + >>> T2,Z2 = linalg.rsf2csf(T,Z) + >>> print T + [[ 9.90012467 1.78947961 -0.65498528] + [ 0. 0.54993766 -1.57754789] + [ 0. 0.51260928 0.54993766]] + >>> print T2 + [[ 9.90012467 +0.00000000e+00j -0.32436598 +1.55463542e+00j + -0.88619748 +5.69027615e-01j] + [ 0.00000000 +0.00000000e+00j 0.54993766 +8.99258408e-01j + 1.06493862 +1.37016050e-17j] + [ 0.00000000 +0.00000000e+00j 0.00000000 +0.00000000e+00j + 0.54993766 -8.99258408e-01j]] + >>> print abs(T1-T2) # different + [[ 1.24357637e-14 2.09205364e+00 6.56028192e-01] + [ 0.00000000e+00 4.00296604e-16 1.83223097e+00] + [ 0.00000000e+00 0.00000000e+00 4.57756680e-16]] + >>> print abs(Z1-Z2) # different + [[ 0.06833781 1.10591375 0.23662249] + [ 0.11857169 0.5585604 0.29617525] + [ 0.12624999 0.75656818 0.22975038]] + >>> T,Z,T1,Z1,T2,Z2 = map(mat,(T,Z,T1,Z1,T2,Z2)) + >>> print abs(A-Z*T*Z.H) # same + [[ 1.11022302e-16 4.44089210e-16 4.44089210e-16] + [ 4.44089210e-16 1.33226763e-15 8.88178420e-16] + [ 8.88178420e-16 4.44089210e-16 2.66453526e-15]] + >>> print abs(A-Z1*T1*Z1.H) # same + [[ 1.00043248e-15 2.22301403e-15 5.55749485e-15] + [ 2.88899660e-15 8.44927041e-15 9.77322008e-15] + [ 3.11291538e-15 1.15463228e-14 1.15464861e-14]] + >>> print abs(A-Z2*T2*Z2.H) # same + [[ 3.34058710e-16 8.88611201e-16 4.18773089e-18] + [ 1.48694940e-16 8.95109973e-16 8.92966151e-16] + [ 1.33228956e-15 1.33582317e-15 3.55373104e-15]] Matrix Functions ---------------- @@ -2141,8 +2606,25 @@ algorithm. For example the following code computes the zeroth-order Bessel function applied to a matrix. -.. literalinclude:: examples/10-4-4 + >>> from scipy import special, random, linalg + >>> A = random.rand(3,3) + >>> B = linalg.funm(A,lambda x: special.jv(0,real(x))) + >>> print A + [[ 0.72578091 0.34105276 0.79570345] + [ 0.65767207 0.73855618 0.541453 ] + [ 0.78397086 0.68043507 0.4837898 ]] + >>> print B + [[ 0.72599893 -0.20545711 -0.22721101] + [-0.27426769 0.77255139 -0.23422637] + [-0.27612103 -0.21754832 0.7556849 ]] + >>> print linalg.eigvals(A) + [ 1.91262611+0.j 0.21846476+0.j -0.18296399+0.j] + >>> print special.jv(0, linalg.eigvals(A)) + [ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] + >>> print linalg.eigvals(B) + [ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] + Statistics ========== From scipy-svn at scipy.org Wed Dec 3 18:24:57 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 3 Dec 2008 17:24:57 -0600 (CST) Subject: [Scipy-svn] r5216 - in trunk/doc: . source/tutorial Message-ID: <20081203232457.57C16C7C009@scipy.org> Author: ptvirtan Date: 2008-12-03 17:24:44 -0600 (Wed, 03 Dec 2008) New Revision: 5216 Modified: trunk/doc/Makefile trunk/doc/source/tutorial/index.rst Log: tutorial: remove, update or comment out parts that are out-of-date. Remove the updating warning Modified: trunk/doc/Makefile =================================================================== --- trunk/doc/Makefile 2008-12-03 23:23:53 UTC (rev 5215) +++ trunk/doc/Makefile 2008-12-03 23:24:44 UTC (rev 5216) @@ -40,7 +40,7 @@ mkdir -p build/dist cp -r build/html build/dist/reference touch build/dist/index.html - perl -pi -e 's#^\s*(
  • SciPy.*?Reference Guide.*?»
  • )$$#
  • Numpy and Scipy Documentation »
  • $$1#;' build/dist/*.html build/dist/*/*.html build/dist/*/*/*.html + perl -pi -e 's#^\s*(
  • SciPy.*?Reference Guide.*?»
  • )\s*$$#
  • Numpy and Scipy Documentation »
  • $$1#;' build/dist/*.html build/dist/*/*.html build/dist/*/*/*.html (cd build/html && zip -9qr ../dist/scipy-html.zip .) cp build/latex/*.pdf build/dist cd build/dist && tar czf ../dist.tar.gz * Modified: trunk/doc/source/tutorial/index.rst =================================================================== --- trunk/doc/source/tutorial/index.rst 2008-12-03 23:23:53 UTC (rev 5215) +++ trunk/doc/source/tutorial/index.rst 2008-12-03 23:24:44 UTC (rev 5216) @@ -6,12 +6,7 @@ .. currentmodule:: scipy -.. warning:: - This is adapted from the old Scipy tutorial, and it is being revised. - Parts of it are still out-of-date. - - Introduction ============ @@ -52,8 +47,13 @@ General Help ------------ -Python provides the facility of documentation strings. The functions -and classes available in SciPy use this method for on-line +Scipy and Numpy have HTML and PDF versions of their documentation +available at http://docs.scipy.org/, which currently details nearly +all available functionality. However, this documentation is still +work-in-progress, and some parts may be incomplete or sparse. + +Python also provides the facility of documentation strings. The +functions and classes available in SciPy use this method for on-line documentation. There are two methods for reading these messages and getting help. Python provides the command :func:`help` in the pydoc module. Entering this command with no arguments (i.e. ``>>> help`` ) @@ -68,9 +68,10 @@ is also available under the command scipy.info. The signature and documentation string for the object passed to the help command are printed to standard output (or to a writeable object passed as the -third argument). The second keyword argument of "scipy.info "defines the maximum width of the line for printing. If a module is -passed as the argument to help than a list of the functions and -classes defined in that module is printed. For example: +third argument). The second keyword argument of "scipy.info" defines +the maximum width of the line for printing. If a module is passed as +the argument to help than a list of the functions and classes defined +in that module is printed. For example: .. literalinclude:: examples/1-1 @@ -86,113 +87,91 @@ ------------------ SciPy is organized into subpackages covering different scientific -computing domains. Many common functions which several subpackages -rely are in :mod:`numpy`. This allows for the possibility of -separately distributing the subpackages of scipy as long as Numpy is -provided as well. +computing domains. These are summarized in the following table: -Two other packages are installed at the higher-level: scipy_distutils -and weave. These two packages while distributed with main scipy -package could see use independently of scipy and so are treated as -separate packages and described elsewhere. +.. currentmodule:: scipy -The remaining subpackages are summarized in the following table (a * -denotes an optional sub-package that requires additional libraries to -function or is not available on all platforms). +================== ===================================================================== +Subpackage Description +================== ===================================================================== +:mod:`cluster` Clustering algorithms +:mod:`constants` Physical and mathematical constants +:mod:`fftpack` Fast Fourier Transform routines +:mod:`integrate` Integration and ordinary differential equation solvers +:mod:`interpolate` Interpolation and smoothing splines +:mod:`io` Input and Output +:mod:`linalg` Linear algebra +:mod:`maxentropy` Maximum entropy methods +:mod:`ndimage` N-dimensional image processing +:mod:`odr` Orthogonal distance regression +:mod:`optimize` Optimization and root-finding routines +:mod:`signal` Signal processing +:mod:`sparse` Sparse matrices and associated routines +:mod:`spatial` Spatial data structures and algorithms +:mod:`special` Special functions +:mod:`stats` Statistical distributions and functions +:mod:`weave` C/C++ integration +================== ===================================================================== - -=========== ===================================================================== -Subpackage Description -=========== ===================================================================== -cluster Clustering algorithms -cow Cluster of Workstations code for parallel programming -fftpack FFT based on fftpack -- default -fftw* FFT based on fftw --- requires FFTW libraries (is this still needed?) -ga Genetic algorithms -gplt* Plotting --- requires gnuplot -integrate Integration -interpolate Interpolation -io Input and Output -linalg Linear algebra -optimize Optimization and root-finding routines -plt* Plotting --- requires wxPython -signal Signal processing -special Special functions -stats Statistical distributions and functions -xplt Plotting with gist -=========== ===================================================================== - - - Because of their ubiquitousness, some of the functions in these subpackages are also made available in the scipy namespace to ease their use in interactive sessions and programs. In addition, many -convenience functions are located in :mod:`numpy` and the in the +basic array functions from :mod:`numpy` are also available at the top-level of the :mod:`scipy` package. Before looking at the sub-packages individually, we will first look at some of these common functions. -Basic functions in Numpy and top-level scipy -============================================ +Basic functions in Numpy (and top-level scipy) +============================================== +.. currentmodule:: numpy + Interaction with Numpy ------------------------ -To begin with, all of the Numpy functions have been subsumed into -the scipy namespace so that all of those functions are available +To begin with, all of the Numpy functions have been subsumed into the +:mod:`scipy` namespace so that all of those functions are available without additionally importing Numpy. In addition, the universal functions (addition, subtraction, division) have been altered to not -raise exceptions if floating-point errors are encountered, -instead NaN's and Inf's are returned in the arrays. To assist in -detection of these events new universal functions (isnan, isfinite, -isinf) have been added. +raise exceptions if floating-point errors are encountered; instead, +NaN's and Inf's are returned in the arrays. To assist in detection of +these events, several functions (:func:`isnan`, :func:`isfinite`, +:func:`isinf`) are available. -In addition, the comparision operators have been changed to allow -comparisons and logical operations of complex numbers (only the real -part is compared). Also, with the new universal functions in SciPy, -the logical operations (except logical_XXX functions) all return -arrays of unsigned bytes (8-bits per element instead of the old -32-bits, or even 64-bits) per element [#]_ . - -In an effort to get a consistency for default arguments, some of the -default arguments have changed from Numpy. The idea is for you to use -scipy as a base package instead of Numpy anyway. - Finally, some of the basic functions like log, sqrt, and inverse trig functions have been modified to return complex numbers instead of NaN's where appropriate (*i.e.* ``scipy.sqrt(-1)`` returns ``1j``). -.. [#] Be careful when treating logical expressions as integers as the 8-bit - integers may silently overflow at 256. - - Top-level scipy routines ------------------------ The purpose of the top level of scipy is to collect general-purpose routines that the other sub-packages can use and to provide a simple -replacement for Numpy. Anytime you might think to import Numpy, -you can import scipy_base instead and remove yourself from direct -dependence on Numpy. These routines are divided into several files -for organizational purposes, but they are all available under the -scipy_base namespace (and the scipy namespace). There are routines for -type handling and type checking, shape and matrix manipulation, -polynomial processing, and other useful functions. Rather than giving -a detailed description of each of these functions (which is available -using the :func:`help`, :func:`info` and :func:`source` commands), -this tutorial will discuss some of the more useful commands which -require a little introduction to use to their full potential. +replacement for Numpy. Anytime you might think to import Numpy, you +can import scipy instead and remove yourself from direct dependence on +Numpy. These routines are divided into several files for +organizational purposes, but they are all available under the numpy +namespace (and the scipy namespace). There are routines for type +handling and type checking, shape and matrix manipulation, polynomial +processing, and other useful functions. Rather than giving a detailed +description of each of these functions (which is available in the +Numpy Reference Guide or by using the :func:`help`, :func:`info` and +:func:`source` commands), this tutorial will discuss some of the more +useful commands which require a little introduction to use to their +full potential. Type handling ^^^^^^^^^^^^^ -Note the difference between :func:`iscomplex` ( :func:`isreal` ) and :func:`iscomplexobj` ( :func:`isrealobj` ). The former command is array based and returns byte arrays of ones -and zeros providing the result of the element-wise test. The latter -command is object based and returns a scalar describing the result of -the test on the entire object. +Note the difference between :func:`iscomplex` (:func:`isreal`) and +:func:`iscomplexobj` (:func:`isrealobj`). The former command is +array based and returns byte arrays of ones and zeros providing the +result of the element-wise test. The latter command is object based +and returns a scalar describing the result of the test on the entire +object. Often it is required to get just the real and/or imaginary part of a complex number. While complex numbers and arrays have attributes that @@ -213,9 +192,8 @@ the use of the :obj:`cast` dictionary. The dictionary is keyed by the type it is desired to cast to and the dictionary stores functions to perform the casting. Thus, ``>>> a = cast['f'](d)`` returns an array -of float32 from d. This function is also useful as an easy way to get -a scalar of a certain type: ``>>> fpi = cast['f'](pi)`` although this -should not be needed if you use alter_numeric(). +of :class:`float32` from *d*. This function is also useful as an easy +way to get a scalar of a certain type: ``>>> fpi = cast['f'](pi)``. Index Tricks @@ -223,7 +201,8 @@ Thre are some class instances that make special use of the slicing functionality to provide efficient means for array construction. This -part will discuss the operation of :obj:`mgrid` , :obj:`ogrid` , :obj:`r_` , and :obj:`c_` for quickly constructing arrays. +part will discuss the operation of :obj:`mgrid` , :obj:`ogrid` , +:obj:`r_` , and :obj:`c_` for quickly constructing arrays. One familiar with Matlab may complain that it is difficult to construct arrays from the interactive session with Python. Suppose, @@ -310,19 +289,11 @@ available. -Matrix manipulations -^^^^^^^^^^^^^^^^^^^^ - -These are functions specifically suited for 2-dimensional arrays that -were part of MLab in the Numpy distribution, but have been placed in -scipy_base for completeness so that users are not importing Numpy. - - Polynomials ^^^^^^^^^^^ There are two (interchangeable) ways to deal with 1-d polynomials in -SciPy. The first is to use the :class:`poly1d` class in Numpy. This +SciPy. The first is to use the :class:`poly1d` class from Numpy. This class accepts coefficients or polynomial roots to initialize a polynomial. The polynomial object can then be manipulated in algebraic expressions, integrated, differentiated, and evaluated. It even prints @@ -353,9 +324,9 @@ Vectorizing functions (vectorize) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -One of the features that SciPy provides is a class :obj:`vectorize` to +One of the features that NumPy provides is a class :obj:`vectorize` to convert an ordinary Python function which accepts scalars and returns -scalars into a "vectorized-function "with the same broadcasting rules +scalars into a "vectorized-function" with the same broadcasting rules as other Numpy functions (*i.e.* the Universal functions, or ufuncs). For example, suppose you have a Python function named :obj:`addsubtract` defined as: @@ -387,20 +358,21 @@ ^^^^^^^^^^^^^^^^^^^^^^ There are several other functions in the scipy_base package including -most of the other functions that are also in MLab that comes with the -Numpy package. The reason for duplicating these functions is to -allow SciPy to potentially alter their original interface and make it -easier for users to know how to get access to functions +most of the other functions that are also in the Numpy package. The +reason for duplicating these functions is to allow SciPy to +potentially alter their original interface and make it easier for +users to know how to get access to functions >>> from scipy import * -New functions which should be mentioned are :obj:`mod(x,y)` which can +Functions which should be mentioned are :obj:`mod(x,y)` which can replace ``x % y`` when it is desired that the result take the sign of *y* instead of *x* . Also included is :obj:`fix` which always rounds to the nearest integer towards zero. For doing phase processing, the functions :func:`angle`, and :obj:`unwrap` are also useful. Also, the :obj:`linspace` and :obj:`logspace` functions return equally spaced samples -in a linear or log scale. Finally, mention should be made of the new +in a linear or log scale. Finally, it's useful to be aware of the indexing +capabilities of Numpy.mention should be made of the new function :obj:`select` which extends the functionality of :obj:`where` to include multiple conditions and multiple choices. The calling convention is ``select(condlist,choicelist,default=0).`` :obj:`select` is @@ -435,16 +407,21 @@ returns a common image used in image processing: :obj:`lena`. Finally, two functions are provided that are useful for approximating -derivatives of functions using discrete-differences. The function :obj:`central_diff_weights` returns weighting coefficients for an equally-spaced :math:`N` -point approximation to the derivative of order :math:`o.` These weights must be multiplied by the function corresponding to -these points and the results added to obtain the derivative -approximation. This function is intended for use when only samples of -the function are avaiable. When the function is an object that can be -handed to a routine and evaluated, the function :obj:`derivative` can be used to automatically evaluate the object at the correct points -to obtain an N-point approximation to the :math:`o^{\textrm{th}}` -derivative at a given point. +derivatives of functions using discrete-differences. The function +:obj:`central_diff_weights` returns weighting coefficients for an +equally-spaced :math:`N`-point approximation to the derivative of +order *o*. These weights must be multiplied by the function +corresponding to these points and the results added to obtain the +derivative approximation. This function is intended for use when only +samples of the function are avaiable. When the function is an object +that can be handed to a routine and evaluated, the function +:obj:`derivative` can be used to automatically evaluate the object at +the correct points to obtain an N-point approximation to the *o*-th +derivative at a given point. -Special functions (special) -=========================== +Special functions (:mod:`scipy.special`) +======================================== .. currentmodule:: scipy.special @@ -459,15 +436,15 @@ broadcasting rules as other math functions in Numerical Python. Many of these functions also accept complex-numbers as input. For a complete list of the available functions with a one-line description -type ``>>> info(special).`` Each function also has it's own +type ``>>> help(special).`` Each function also has it's own documentation accessible using help. If you don't see a function you need, consider writing it and contributing it to the library. You can write the function in either C, Fortran, or Python. Look in the source code of the library for examples of each of these kind of functions. -Integration (integrate) -======================= +Integration (:mod:`scipy.integrate`) +==================================== .. currentmodule:: scipy.integrate @@ -478,8 +455,8 @@ .. literalinclude:: examples/4-1 -General integration (integrate.quad) ------------------------------------- +General integration (:func:`quad`) +---------------------------------- The function :obj:`quad` is provided to integrate a function of one variable between two points. The points can be :math:`\pm\infty` @@ -506,7 +483,8 @@ >>> print abs(result[0]-I) 1.03761443881e-11 -The first argument to quad is a "callable "Python object ( *i.e* a function, method, or class instance). Notice the use of a lambda- +The first argument to quad is a "callable" Python object (*i.e* a +function, method, or class instance). Notice the use of a lambda- function in this case as the argument. The next two arguments are the limits of integration. The return value is a tuple, with the first element holding the estimated value of the integral and the second @@ -610,42 +588,49 @@ :mod:`special.orthogonal` which can calculate the roots and quadrature weights of a large variety of orthogonal polynomials (the polynomials themselves are available as special functions returning instances of -the polynomial class --- e.g. ``special.legendre`` ). +the polynomial class --- e.g. :obj:`special.legendre `). Integrating using samples ------------------------- -There are three functions for computing integrals given only samples: :obj:`trapz` , :obj:`simps` , and :obj:`romb` . The first two functions use Newton-Coates formulas of order 1 and 2 -respectively to perform integration. These two functions can handle, +There are three functions for computing integrals given only samples: +:obj:`trapz` , :obj:`simps`, and :obj:`romb` . The first two +functions use Newton-Coates formulas of order 1 and 2 respectively to +perform integration. These two functions can handle, non-equally-spaced samples. The trapezoidal rule approximates the function as a straight line between adjacent points, while Simpson's rule approximates the function between three adjacent points as a parabola. If the samples are equally-spaced and the number of samples available -is :math:`2^{k}+1` for some integer :math:`k` , then Romberg integration can be used to obtain high-precision -estimates of the integral using the available samples. Romberg -integration uses the trapezoid rule at step-sizes related by a power -of two and then performs Richardson extrapolation on these estimates -to approximate the integral with a higher-degree of accuracy. (A -different interface to Romberg integration useful when the function -can be provided is also available as :func:`integrate.romberg`). +is :math:`2^{k}+1` for some integer :math:`k`, then Romberg +integration can be used to obtain high-precision estimates of the +integral using the available samples. Romberg integration uses the +trapezoid rule at step-sizes related by a power of two and then +performs Richardson extrapolation on these estimates to approximate +the integral with a higher-degree of accuracy. (A different interface +to Romberg integration useful when the function can be provided is +also available as :func:`romberg`). -Ordinary differential equations (integrate.odeint) --------------------------------------------------- +Ordinary differential equations (:func:`odeint`) +------------------------------------------------ Integrating a set of ordinary differential equations (ODEs) given -initial conditions is another useful example. The function :obj:`odeint` is available in SciPy for integrating a first-order vector -differential equation: +initial conditions is another useful example. The function +:obj:`odeint` is available in SciPy for integrating a first-order +vector differential equation: .. math:: :nowrap: \[ \frac{d\mathbf{y}}{dt}=\mathbf{f}\left(\mathbf{y},t\right),\] -given initial conditions :math:`\mathbf{y}\left(0\right)=y_{0},` where :math:`\mathbf{y}` is a length :math:`N` vector and :math:`\mathbf{f}` is a mapping from :math:`\mathcal{R}^{N}` to :math:`\mathcal{R}^{N}.` A higher-order ordinary differential equation can always be reduced to +given initial conditions :math:`\mathbf{y}\left(0\right)=y_{0}`, where +:math:`\mathbf{y}` is a length :math:`N` vector and :math:`\mathbf{f}` +is a mapping from :math:`\mathcal{R}^{N}` to :math:`\mathcal{R}^{N}.` +A higher-order ordinary differential equation can always be reduced to a differential equation of this type by introducing intermediate derivatives into the :math:`\mathbf{y}` vector. @@ -665,9 +650,11 @@ \[ w=\textrm{Ai}\left(z\right),\] -which gives a means to check the integrator using :func:`special.airy`. +which gives a means to check the integrator using :func:`special.airy `. -First, convert this ODE into standard form by setting :math:`\mathbf{y}=\left[\frac{dw}{dz},w\right]` and :math:`t=z.` Thus, the differential equation becomes +First, convert this ODE into standard form by setting +:math:`\mathbf{y}=\left[\frac{dw}{dz},w\right]` and :math:`t=z`. Thus, +the differential equation becomes .. math:: :nowrap: @@ -681,9 +668,9 @@ \[ \mathbf{f}\left(\mathbf{y},t\right)=\mathbf{A}\left(t\right)\mathbf{y}.\] - - -As an interesting reminder, if :math:`\mathbf{A}\left(t\right)` commutes with :math:`\int_{0}^{t}\mathbf{A}\left(\tau\right)\, d\tau` under matrix multiplication, then this linear differential equation +As an interesting reminder, if :math:`\mathbf{A}\left(t\right)` +commutes with :math:`\int_{0}^{t}\mathbf{A}\left(\tau\right)\, d\tau` +under matrix multiplication, then this linear differential equation has an exact solution using the matrix exponential: .. math:: @@ -739,6 +726,8 @@ Optimization (optimize) ======================= +.. currentmodule:: scipy.optimize + There are several classical optimization algorithms provided by SciPy in the :mod:`scipy.optimize` package. An overview of the module is available using :func:`help` (or :func:`pydoc.help`): @@ -746,17 +735,16 @@ .. literalinclude:: examples/5-1 The first four algorithms are unconstrained minimization algorithms -(fmin: Nelder-Mead simplex, fmin_bfgs: BFGS, fmin_ncg: Newton -Conjugate Gradient, and leastsq: Levenburg-Marquardt). The fourth -algorithm only works for functions of a single variable but allows -minimization over a specified interval. The last algorithm actually -finds the roots of a general function of possibly many variables. It -is included in the optimization package because at the (non-boundary) -extreme points of a function, the gradient is equal to zero. +(:func:`fmin`: Nelder-Mead simplex, :func:`fmin_bfgs`: BFGS, +:func:`fmin_ncg`: Newton Conjugate Gradient, and :func:`leastsq`: +Levenburg-Marquardt). The last algorithm actually finds the roots of a +general function of possibly many variables. It is included in the +optimization package because at the (non-boundary) extreme points of a +function, the gradient is equal to zero. -Nelder-Mead Simplex algorithm (optimize.fmin) ---------------------------------------------- +Nelder-Mead Simplex algorithm (:func:`fmin`) +-------------------------------------------- The simplex algorithm is probably the simplest way to minimize a fairly well-behaved function. The simplex algorithm requires only @@ -789,11 +777,11 @@ [ 1. 1. 1. 1. 1.] Another optimization algorithm that needs only function calls to find -the minimum is Powell's method available as :func:`optimize.fmin_powell`. +the minimum is Powell's method available as :func:`fmin_powell`. -Broyden-Fletcher-Goldfarb-Shanno algorithm (optimize.fmin_bfgs) ---------------------------------------------------------------- +Broyden-Fletcher-Goldfarb-Shanno algorithm (:func:`fmin_bfgs`) +-------------------------------------------------------------- In order to converge more quickly to the solution, this routine uses the gradient of the objective function. If the gradient is not given @@ -849,8 +837,8 @@ [ 1. 1. 1. 1. 1.] -Newton-Conjugate-Gradient (optimize.fmin_ncg) ---------------------------------------------- +Newton-Conjugate-Gradient (:func:`fmin_ncg`) +-------------------------------------------- The method which requires the fewest function calls and is therefore often the fastest method to minimize functions of many variables is @@ -983,16 +971,20 @@ [ 1. 1. 1. 1. 1.] -Least-square fitting (minimize.leastsq) ---------------------------------------- +Least-square fitting (:func:`leastsq`) +-------------------------------------- All of the previously-explained minimization procedures can be used to solve a least-squares problem provided the appropriate objective function is constructed. For example, suppose it is desired to fit a -set of data :math:`\left\{ \mathbf{x}_{i},\mathbf{y}_{i}\right\} ` to a known model, :math:`\mathbf{y}=\mathbf{f}\left(\mathbf{x},\mathbf{p}\right)` where :math:`\mathbf{p}` is a vector of parameters for the model that need to be found. A -common method for determining which parameter vector gives the best -fit to the data is to minimize the sum of squares of the residuals. -The residual is usually defined for each observed data-point as +set of data :math:`\left\{\mathbf{x}_{i}, \mathbf{y}_{i}\right\}` +to a known model, +:math:`\mathbf{y}=\mathbf{f}\left(\mathbf{x},\mathbf{p}\right)` +where :math:`\mathbf{p}` is a vector of parameters for the model that +need to be found. A common method for determining which parameter +vector gives the best fit to the data is to minimize the sum of squares +of the residuals. The residual is usually defined for each observed +data-point as .. math:: :nowrap: @@ -1009,8 +1001,12 @@ -The :obj:`leastsq` algorithm performs this squaring and summing of the residuals -automatically. It takes as an input argument the vector function :math:`\mathbf{e}\left(\mathbf{p}\right)` and returns the value of :math:`\mathbf{p}` which minimizes :math:`J\left(\mathbf{p}\right)=\mathbf{e}^{T}\mathbf{e}` directly. The user is also encouraged to provide the Jacobian matrix +The :obj:`leastsq` algorithm performs this squaring and summing of the +residuals automatically. It takes as an input argument the vector +function :math:`\mathbf{e}\left(\mathbf{p}\right)` and returns the +value of :math:`\mathbf{p}` which minimizes +:math:`J\left(\mathbf{p}\right)=\mathbf{e}^{T}\mathbf{e}` +directly. The user is also encouraged to provide the Jacobian matrix of the function (with derivatives down the columns or across the rows). If the Jacobian is not provided, it is estimated. @@ -1081,8 +1077,8 @@ been developed that can work faster. -Unconstrained minimization (optimize.brent) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Unconstrained minimization (:func:`brent`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There are actually two methods that can be used to minimize a scalar function (:obj:`brent` and :func:`golden`), but :obj:`golden` is @@ -1098,16 +1094,16 @@ for your function and result in an unexpected minimum being returned). -Bounded minimization (optimize.fminbound) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Bounded minimization (:func:`fminbound`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Thus far all of the minimization routines described have been unconstrained minimization routines. Very often, however, there are constraints that can be placed on the solution space before -minimization occurs. The :obj:`fminbound` function is an example of a constrained minimization procedure that -provides a rudimentary interval constraint for scalar functions. The -interval constraint allows the minimization to occur only between two -fixed endpoints. +minimization occurs. The :obj:`fminbound` function is an example of a +constrained minimization procedure that provides a rudimentary +interval constraint for scalar functions. The interval constraint +allows the minimization to occur only between two fixed endpoints. For example, to find the minimum of :math:`J_{1}\left(x\right)` near :math:`x=5` , :obj:`fminbound` can be called using the interval :math:`\left[4,7\right]` as a constraint. The result is :math:`x_{\textrm{min}}=5.3314` : @@ -1125,9 +1121,11 @@ Sets of equations ^^^^^^^^^^^^^^^^^ -To find the roots of a polynomial, the command :obj:`roots` is useful. To find a root of a set of non-linear equations, the -command :obj:`optimize.fsolve` is needed. For example, the following example finds the roots of the -single-variable transcendental equation +To find the roots of a polynomial, the command :obj:`roots +` is useful. To find a root of a set of non-linear +equations, the command :obj:`fsolve` is needed. For example, the +following example finds the roots of the single-variable +transcendental equation .. math:: :nowrap: @@ -1168,8 +1166,9 @@ If one has a single-variable equation, there are four different root finder algorithms that can be tried. Each of these root finding algorithms requires the endpoints of an interval where a root is -suspected (because the function changes signs). In general :obj:`brentq` is the best choice, but the other methods may be useful in certain -circumstances or for academic purposes. +suspected (because the function changes signs). In general +:obj:`brentq` is the best choice, but the other methods may be useful +in certain circumstances or for academic purposes. Fixed-point solving @@ -1178,13 +1177,20 @@ A problem closely related to finding the zeros of a function is the problem of finding a fixed-point of a function. A fixed point of a function is the point at which evaluation of the function returns the -point: :math:`g\left(x\right)=x.` Clearly the fixed point of :math:`g` is the root of :math:`f\left(x\right)=g\left(x\right)-x.` Equivalently, the root of :math:`f` is the fixed_point of :math:`g\left(x\right)=f\left(x\right)+x.` The routine :obj:`fixed_point` provides a simple iterative method using Aitkens sequence acceleration -to estimate the fixed point of :math:`g` given a starting point. +point: :math:`g\left(x\right)=x.` Clearly the fixed point of :math:`g` +is the root of :math:`f\left(x\right)=g\left(x\right)-x.` +Equivalently, the root of :math:`f` is the fixed_point of +:math:`g\left(x\right)=f\left(x\right)+x.` The routine +:obj:`fixed_point` provides a simple iterative method using Aitkens +sequence acceleration to estimate the fixed point of :math:`g` given a +starting point. -Interpolation (interpolate) -=========================== +Interpolation (:mod:`scipy.interpolate`) +======================================== +.. currentmodule:: scipy.interpolate + There are two general interpolation facilities available in SciPy. The first facility is an interpolation class which performs linear 1-dimensional interpolation. The second facility is based on the @@ -1192,19 +1198,19 @@ 2-dimensional (smoothed) cubic-spline interpolation. -Linear 1-d interpolation (interpolate.interp1d) ------------------------------------------------ +Linear 1-d interpolation (:class:`interp1d`) +-------------------------------------------- The interp1d class in scipy.interpolate is a convenient method to create a function based on fixed data points which can be evaluated anywhere within the domain defined by the given data using linear interpolation. An instance of this class is created by passing the 1-d vectors comprising the data. The instance of this class defines a -*__call__* method and can therefore by treated like a function which -interpolates between known data values to obtain unknown values (it -even has a docstring for help). Behavior at the boundary can be -specified at instantiation time. The following example demonstrates -it's use. +:meth:`__call__ ` method and can therefore by +treated like a function which interpolates between known data values +to obtain unknown values (it also has a docstring for help). Behavior +at the boundary can be specified at instantiation time. The following +example demonstrates it's use. .. plot:: @@ -1232,7 +1238,7 @@ representation, there are two different was to represent a curve and obtain (smoothing) spline coefficients: directly and parametrically. The direct method finds the spline representation of a curve in a two- -dimensional plane using the function :obj:`interpolate.splrep`. The +dimensional plane using the function :obj:`splrep`. The first two arguments are the only ones required, and these provide the :math:`x` and :math:`y` components of the curve. The normal output is a 3-tuple, :math:`\left(t,c,k\right)` , containing the knot-points, @@ -1241,7 +1247,7 @@ with the input keyword, *k.* For curves in :math:`N` -dimensional space the function -:obj:`interpolate.splprep` allows defining the curve +:obj:`splprep` allows defining the curve parametrically. For this function only 1 input argument is required. This input is a list of :math:`N` -arrays representing the curve in :math:`N` -dimensional space. The length of each array is the @@ -1261,12 +1267,12 @@ Once the spline representation of the data has been determined, functions are available for evaluating the spline -(:func:`interpolate.splev`) and its derivatives -(:func:`interpolate.splev`, :func:`interpolate.splade`) at any point +(:func:`splev`) and its derivatives +(:func:`splev`, :func:`splade`) at any point and the integral of the spline between any two points ( -:func:`interpolate.splint`). In addition, for cubic splines ( :math:`k=3` +:func:`splint`). In addition, for cubic splines ( :math:`k=3` ) with 8 or more knots, the roots of the spline can be estimated ( -:func:`interpolate.sproot`). These functions are demonstrated in the +:func:`sproot`). These functions are demonstrated in the example that follows. .. plot:: @@ -1339,31 +1345,31 @@ >>> plt.show() -Two-dimensional spline representation (interpolate.bisplrep) ------------------------------------------------------------- +Two-dimensional spline representation (:func:`bisplrep`) +-------------------------------------------------------- For (smooth) spline-fitting to a two dimensional surface, the function -:obj:`interpolate.bisplrep` is available. This function takes as -required inputs the **1-D** arrays *x*, *y*, and *z* which represent -points on the surface :math:`z=f\left(x,y\right).` The default output -is a list :math:`\left[tx,ty,c,kx,ky\right]` whose entries represent +:func:`bisplrep` is available. This function takes as required inputs +the **1-D** arrays *x*, *y*, and *z* which represent points on the +surface :math:`z=f\left(x,y\right).` The default output is a list +:math:`\left[tx,ty,c,kx,ky\right]` whose entries represent respectively, the components of the knot positions, the coefficients of the spline, and the order of the spline in each coordinate. It is convenient to hold this list in a single object, *tck,* so that it can -be passed easily to the function :obj:`interpolate.bisplev`. The +be passed easily to the function :obj:`bisplev`. The keyword, *s* , can be used to change the amount of smoothing performed on the data while determining the appropriate spline. The default value is :math:`s=m-\sqrt{2m}` where :math:`m` is the number of data points in the *x, y,* and *z* vectors. As a result, if no smoothing is desired, then :math:`s=0` should be passed to -:obj:`interpolate.bisplrep` . +:obj:`bisplrep` . To evaluate the two-dimensional spline and it's partial derivatives (up to the order of the spline), the function -:obj:`interpolate.bisplev` is required. This function takes as the +:obj:`bisplev` is required. This function takes as the first two arguments **two 1-D arrays** whose cross-product specifies the domain over which to evaluate the spline. The third argument is -the *tck* list returned from :obj:`interpolate.bisplrep`. If desired, +the *tck* list returned from :obj:`bisplrep`. If desired, the fourth and fifth arguments provide the orders of the partial derivative in the :math:`x` and :math:`y` direction respectively. @@ -1373,13 +1379,14 @@ processing toolbox contains more appropriate algorithms for finding the spline representation of an image. The two dimensional interpolation commands are intended for use when interpolating a two -dimensional function as shown in the example that follows (See also -Figure `4 <#fig-2d-interp>`__ ). This example uses the :obj:`mgrid` command in SciPy which is useful for defining a "mesh-grid "in many dimensions. (See also the :obj:`ogrid` command if the full-mesh is not needed). The number of output -arguments and the number of dimensions of each argument is determined -by the number of indexing objects passed in :obj:`mgrid`[]. +dimensional function as shown in the example that follows. This +example uses the :obj:`mgrid ` command in SciPy which is +useful for defining a "mesh-grid "in many dimensions. (See also the +:obj:`ogrid ` command if the full-mesh is not +needed). The number of output arguments and the number of dimensions +of each argument is determined by the number of indexing objects +passed in :obj:`mgrid `[]. -.. _`fig:2d_interp`: - .. plot:: >>> from numpy import * @@ -1528,8 +1535,6 @@ :obj:`signal.convolve2d` which convolves arbitrary two-dimensional filters and allows for choosing mirror-symmetric boundary conditions. -.. _`fig:lena_edge_spline`: - .. plot:: >>> from numpy import * @@ -1602,7 +1607,11 @@ This equation can only be implemented directly if we limit the sequences to finite support sequences that can be stored in a -computer, choose :math:`n=0` to be the starting point of both sequences, let :math:`K+1` be that value for which :math:`y\left[n\right]=0` for all :math:`n>K+1` and :math:`M+1` be that value for which :math:`x\left[n\right]=0` for all :math:`n>M+1` , then the discrete convolution expression is +computer, choose :math:`n=0` to be the starting point of both +sequences, let :math:`K+1` be that value for which +:math:`y\left[n\right]=0` for all :math:`n>K+1` and :math:`M+1` be +that value for which :math:`x\left[n\right]=0` for all :math:`n>M+1` , +then the discrete convolution expression is .. math:: :nowrap: @@ -1618,12 +1627,25 @@ Thus, the full discrete convolution of two finite sequences of lengths :math:`K+1` and :math:`M+1` respectively results in a finite sequence of length :math:`K+M+1=\left(K+1\right)+\left(M+1\right)-1.` -One dimensional convolution is implemented in SciPy with the function ``signal.convolve`` . This function takes as inputs the signals :math:`x,` :math:`h` , and an optional flag and returns the signal :math:`y.` The optional flag allows for specification of which part of the output -signal to return. The default value of 'full' returns the entire -signal. If the flag has a value of 'same' then only the middle :math:`K` values are returned starting at :math:`y\left[\left\lfloor \frac{M-1}{2}\right\rfloor \right]` so that the output has the same length as the largest input. If the -flag has a value of 'valid' then only the middle :math:`K-M+1=\left(K+1\right)-\left(M+1\right)+1` output values are returned where :math:`z` depends on all of the values of the smallest input from :math:`h\left[0\right]` to :math:`h\left[M\right].` In other words only the values :math:`y\left[M\right]` to :math:`y\left[K\right]` inclusive are returned. +One dimensional convolution is implemented in SciPy with the function +``signal.convolve`` . This function takes as inputs the signals +:math:`x,` :math:`h` , and an optional flag and returns the signal +:math:`y.` The optional flag allows for specification of which part of +the output signal to return. The default value of 'full' returns the +entire signal. If the flag has a value of 'same' then only the middle +:math:`K` values are returned starting at :math:`y\left[\left\lfloor +\frac{M-1}{2}\right\rfloor \right]` so that the output has the same +length as the largest input. If the flag has a value of 'valid' then +only the middle :math:`K-M+1=\left(K+1\right)-\left(M+1\right)+1` +output values are returned where :math:`z` depends on all of the +values of the smallest input from :math:`h\left[0\right]` to +:math:`h\left[M\right].` In other words only the values +:math:`y\left[M\right]` to :math:`y\left[K\right]` inclusive are +returned. -This same function ``signal.convolve`` can actually take :math:`N` -dimensional arrays as inputs and will return the :math:`N` -dimensional convolution of the two arrays. The same input flags are +This same function ``signal.convolve`` can actually take :math:`N` +-dimensional arrays as inputs and will return the :math:`N` +-dimensional convolution of the two arrays. The same input flags are available for that case as well. Correlation is very similar to convolution except for the minus sign @@ -1650,19 +1672,29 @@ -The SciPy function ``signal.correlate`` implements this operation. Equivalent flags are available for this -operation to return the full :math:`K+M+1` length sequence ('full') or a sequence with the same size as the -largest sequence starting at :math:`w\left[-K+\left\lfloor \frac{M-1}{2}\right\rfloor \right]` ('same') or a sequence where the values depend on all the values of -the smallest sequence ('valid'). This final option returns the :math:`K-M+1` values :math:`w\left[M-K\right]` to :math:`w\left[0\right]` inclusive. +The SciPy function ``signal.correlate`` implements this +operation. Equivalent flags are available for this operation to return +the full :math:`K+M+1` length sequence ('full') or a sequence with the +same size as the largest sequence starting at +:math:`w\left[-K+\left\lfloor \frac{M-1}{2}\right\rfloor \right]` +('same') or a sequence where the values depend on all the values of +the smallest sequence ('valid'). This final option returns the +:math:`K-M+1` values :math:`w\left[M-K\right]` to +:math:`w\left[0\right]` inclusive. -The function :obj:`signal.correlate` can also take arbitrary :math:`N` -dimensional arrays as input and return the :math:`N` -dimensional convolution of the two arrays on output. +The function :obj:`signal.correlate` can also take arbitrary :math:`N` +-dimensional arrays as input and return the :math:`N` -dimensional +convolution of the two arrays on output. -When :math:`N=2,` :obj:`signal.correlate` and/or :obj:`signal.convolve` can be used to construct arbitrary image filters to perform actions -such as blurring, enhancing, and edge-detection for an image. +When :math:`N=2,` :obj:`signal.correlate` and/or +:obj:`signal.convolve` can be used to construct arbitrary image +filters to perform actions such as blurring, enhancing, and +edge-detection for an image. Convolution is mainly used for filtering when one of the signals is -much smaller than the other ( :math:`K\gg M` ), otherwise linear filtering is more easily accomplished in the -frequency domain (see Fourier Transforms). +much smaller than the other ( :math:`K\gg M` ), otherwise linear +filtering is more easily accomplished in the frequency domain (see +Fourier Transforms). Difference-equation filtering @@ -1676,9 +1708,15 @@ \[ \sum_{k=0}^{N}a_{k}y\left[n-k\right]=\sum_{k=0}^{M}b_{k}x\left[n-k\right]\] -where :math:`x\left[n\right]` is the input sequence and :math:`y\left[n\right]` is the output sequence. If we assume initial rest so that :math:`y\left[n\right]=0` for :math:`n<0` , then this kind of filter can be implemented using convolution. -However, the convolution filter sequence :math:`h\left[n\right]` could be infinite if :math:`a_{k}\neq0` for :math:`k\geq1.` In addition, this general class of linear filter allows initial -conditions to be placed on :math:`y\left[n\right]` for :math:`n<0` resulting in a filter that cannot be expressed using convolution. +where :math:`x\left[n\right]` is the input sequence and +:math:`y\left[n\right]` is the output sequence. If we assume initial +rest so that :math:`y\left[n\right]=0` for :math:`n<0` , then this +kind of filter can be implemented using convolution. However, the +convolution filter sequence :math:`h\left[n\right]` could be infinite +if :math:`a_{k}\neq0` for :math:`k\geq1.` In addition, this general +class of linear filter allows initial conditions to be placed on +:math:`y\left[n\right]` for :math:`n<0` resulting in a filter that +cannot be expressed using convolution. The difference equation filter can be thought of as finding :math:`y\left[n\right]` recursively in terms of it's previous values @@ -1687,28 +1725,46 @@ \[ a_{0}y\left[n\right]=-a_{1}y\left[n-1\right]-\cdots-a_{N}y\left[n-N\right]+\cdots+b_{0}x\left[n\right]+\cdots+b_{M}x\left[n-M\right].\] -Often :math:`a_{0}=1` is chosen for normalization. The implementation in SciPy of this -general difference equation filter is a little more complicated then -would be implied by the previous equation. It is implemented so that -only one signal needs to be delayed. The actual implementation -equations are (assuming :math:`a_{0}=1` ). +Often :math:`a_{0}=1` is chosen for normalization. The implementation +in SciPy of this general difference equation filter is a little more +complicated then would be implied by the previous equation. It is +implemented so that only one signal needs to be delayed. The actual +implementation equations are (assuming :math:`a_{0}=1` ). .. math:: :nowrap: \begin{eqnarray*} y\left[n\right] & = & b_{0}x\left[n\right]+z_{0}\left[n-1\right]\\ z_{0}\left[n\right] & = & b_{1}x\left[n\right]+z_{1}\left[n-1\right]-a_{1}y\left[n\right]\\ z_{1}\left[n\right] & = & b_{2}x\left[n\right]+z_{2}\left[n-1\right]-a_{2}y\left[n\right]\\ \vdots & \vdots & \vdots\\ z_{K-2}\left[n\right] & = & b_{K-1}x\left[n\right]+z_{K-1}\left[n-1\right]-a_{K-1}y\left[n\right]\\ z_{K-1}\left[n\right] & = & b_{K}x\left[n\right]-a_{K}y\left[n\right],\end{eqnarray*} -where :math:`K=\max\left(N,M\right).` Note that :math:`b_{K}=0` if :math:`K>M` and :math:`a_{K}=0` if :math:`K>N.` In this way, the output at time :math:`n` depends only on the input at time :math:`n` and the value of :math:`z_{0}` at the previous time. This can always be calculated as long as the :math:`K` values :math:`z_{0}\left[n-1\right]\ldots z_{K-1}\left[n-1\right]` are computed and stored at each time step. +where :math:`K=\max\left(N,M\right).` Note that :math:`b_{K}=0` if +:math:`K>M` and :math:`a_{K}=0` if :math:`K>N.` In this way, the +output at time :math:`n` depends only on the input at time :math:`n` +and the value of :math:`z_{0}` at the previous time. This can always +be calculated as long as the :math:`K` values +:math:`z_{0}\left[n-1\right]\ldots z_{K-1}\left[n-1\right]` are +computed and stored at each time step. -The difference-equation filter is called using the command :obj:`signal.lfilter` in SciPy. This command takes as inputs the vector :math:`b,` the vector, :math:`a,` a signal :math:`x` and returns the vector :math:`y` (the same length as :math:`x` ) computed using the equation given above. If :math:`x` is :math:`N` -dimensional, then the filter is computed along the axis provided. If, -desired, initial conditions providing the values of :math:`z_{0}\left[-1\right]` to :math:`z_{K-1}\left[-1\right]` can be provided or else it will be assumed that they are all zero. If -initial conditions are provided, then the final conditions on the -intermediate variables are also returned. These could be used, for -example, to restart the calculation in the same state. +The difference-equation filter is called using the command +:obj:`signal.lfilter` in SciPy. This command takes as inputs the +vector :math:`b,` the vector, :math:`a,` a signal :math:`x` and +returns the vector :math:`y` (the same length as :math:`x` ) computed +using the equation given above. If :math:`x` is :math:`N` +-dimensional, then the filter is computed along the axis provided. If, +desired, initial conditions providing the values of +:math:`z_{0}\left[-1\right]` to :math:`z_{K-1}\left[-1\right]` can be +provided or else it will be assumed that they are all zero. If initial +conditions are provided, then the final conditions on the intermediate +variables are also returned. These could be used, for example, to +restart the calculation in the same state. Sometimes it is more convenient to express the initial conditions in -terms of the signals :math:`x\left[n\right]` and :math:`y\left[n\right].` In other words, perhaps you have the values of :math:`x\left[-M\right]` to :math:`x\left[-1\right]` and the values of :math:`y\left[-N\right]` to :math:`y\left[-1\right]` and would like to determine what values of :math:`z_{m}\left[-1\right]` should be delivered as initial conditions to the difference-equation -filter. It is not difficult to show that for :math:`0\leq m`. If you are going to be doing a lot of matrix-math, it +is convenient to convert arrays into matrices using this command. One +advantage of using the :func:`mat` command is that you can enter +two-dimensional matrices using MATLAB-like syntax with commas or +spaces separating columns and semicolons separting rows as long as the +matrix is placed in a string passed to :obj:`mat` . Basic routines @@ -1937,9 +2002,13 @@ Finding Inverse ^^^^^^^^^^^^^^^ -The inverse of a matrix :math:`\mathbf{A}` is the matrix :math:`\mathbf{B}` such that :math:`\mathbf{AB}=\mathbf{I}` where :math:`\mathbf{I}` is the identity matrix consisting of ones down the main diagonal. -Usually :math:`\mathbf{B}` is denoted :math:`\mathbf{B}=\mathbf{A}^{-1}` . In SciPy, the matrix inverse of the Numpy array, A, is obtained -using :obj:`linalg.inv` ``(A)`` , or using ``A.I`` if ``A`` is a Matrix. For example, let +The inverse of a matrix :math:`\mathbf{A}` is the matrix +:math:`\mathbf{B}` such that :math:`\mathbf{AB}=\mathbf{I}` where +:math:`\mathbf{I}` is the identity matrix consisting of ones down the +main diagonal. Usually :math:`\mathbf{B}` is denoted +:math:`\mathbf{B}=\mathbf{A}^{-1}` . In SciPy, the matrix inverse of +the Numpy array, A, is obtained using :obj:`linalg.inv` ``(A)`` , or +using ``A.I`` if ``A`` is a Matrix. For example, let .. math:: :nowrap: @@ -2011,7 +2080,13 @@ Finding Determinant ^^^^^^^^^^^^^^^^^^^ -The determinant of a square matrix :math:`\mathbf{A}` is often denoted :math:`\left|\mathbf{A}\right|` and is a quantity often used in linear algebra. Suppose :math:`a_{ij}` are the elements of the matrix :math:`\mathbf{A}` and let :math:`M_{ij}=\left|\mathbf{A}_{ij}\right|` be the determinant of the matrix left by removing the :math:`i^{\textrm{th}}` row and :math:`j^{\textrm{th}}` column from :math:`\mathbf{A}` . Then for any row :math:`i,` +The determinant of a square matrix :math:`\mathbf{A}` is often denoted +:math:`\left|\mathbf{A}\right|` and is a quantity often used in linear +algebra. Suppose :math:`a_{ij}` are the elements of the matrix +:math:`\mathbf{A}` and let :math:`M_{ij}=\left|\mathbf{A}_{ij}\right|` +be the determinant of the matrix left by removing the +:math:`i^{\textrm{th}}` row and :math:`j^{\textrm{th}}` column from +:math:`\mathbf{A}` . Then for any row :math:`i,` .. math:: :nowrap: @@ -2046,9 +2121,10 @@ Matrix and vector norms can also be computed with SciPy. A wide range of norm definitions are available using different parameters to the -order argument of :obj:`linalg.norm` . This function takes a rank-1 (vectors) or a rank-2 (matrices) array -and an optional order argument (default is 2). Based on these inputs a -vector or matrix norm of the requested order is computed. +order argument of :obj:`linalg.norm` . This function takes a rank-1 +(vectors) or a rank-2 (matrices) array and an optional order argument +(default is 2). Based on these inputs a vector or matrix norm of the +requested order is computed. For vector *x* , the order parameter can be any real number including ``inf`` or ``-inf``. The computed norm is @@ -2076,15 +2152,18 @@ Linear least-squares problems occur in many branches of applied mathematics. In this problem a set of linear scaling coefficients is sought that allow a model to fit data. In particular it is assumed -that data :math:`y_{i}` is related to data :math:`\mathbf{x}_{i}` through a set of coefficients :math:`c_{j}` and model functions :math:`f_{j}\left(\mathbf{x}_{i}\right)` via the model +that data :math:`y_{i}` is related to data :math:`\mathbf{x}_{i}` +through a set of coefficients :math:`c_{j}` and model functions +:math:`f_{j}\left(\mathbf{x}_{i}\right)` via the model .. math:: :nowrap: \[ y_{i}=\sum_{j}c_{j}f_{j}\left(\mathbf{x}_{i}\right)+\epsilon_{i}\] -where :math:`\epsilon_{i}` represents uncertainty in the data. The strategy of least squares is -to pick the coefficients :math:`c_{j}` to minimize +where :math:`\epsilon_{i}` represents uncertainty in the data. The +strategy of least squares is to pick the coefficients :math:`c_{j}` to +minimize .. math:: :nowrap: @@ -2121,25 +2200,35 @@ \[ \mathbf{c}=\left(\mathbf{A}^{H}\mathbf{A}\right)^{-1}\mathbf{A}^{H}\mathbf{y}=\mathbf{A}^{\dagger}\mathbf{y}\] -where :math:`\mathbf{A}^{\dagger}` is called the pseudo-inverse of :math:`\mathbf{A}.` Notice that using this definition of :math:`\mathbf{A}` the model can be written +where :math:`\mathbf{A}^{\dagger}` is called the pseudo-inverse of +:math:`\mathbf{A}.` Notice that using this definition of +:math:`\mathbf{A}` the model can be written .. math:: :nowrap: \[ \mathbf{y}=\mathbf{Ac}+\boldsymbol{\epsilon}.\] -The command :obj:`linalg.lstsq` will solve the linear least squares problem for :math:`\mathbf{c}` given :math:`\mathbf{A}` and :math:`\mathbf{y}` . In addition :obj:`linalg.pinv` or :obj:`linalg.pinv2` (uses a different method based on singular value decomposition) will -find :math:`\mathbf{A}^{\dagger}` given :math:`\mathbf{A}.` +The command :obj:`linalg.lstsq` will solve the linear least squares +problem for :math:`\mathbf{c}` given :math:`\mathbf{A}` and +:math:`\mathbf{y}` . In addition :obj:`linalg.pinv` or +:obj:`linalg.pinv2` (uses a different method based on singular value +decomposition) will find :math:`\mathbf{A}^{\dagger}` given +:math:`\mathbf{A}.` -The following example and figure demonstrate the use of :obj:`linalg.lstsq` and :obj:`linalg.pinv` for solving a data-fitting problem. The data shown below were -generated using the model: +The following example and figure demonstrate the use of +:obj:`linalg.lstsq` and :obj:`linalg.pinv` for solving a data-fitting +problem. The data shown below were generated using the model: .. math:: :nowrap: \[ y_{i}=c_{1}e^{-x_{i}}+c_{2}x_{i}\] -where :math:`x_{i}=0.1i` for :math:`i=1\ldots10` , :math:`c_{1}=5` , and :math:`c_{2}=4.` Noise is added to :math:`y_{i}` and the coefficients :math:`c_{1}` and :math:`c_{2}` are estimated using linear least squares. +where :math:`x_{i}=0.1i` for :math:`i=1\ldots10` , :math:`c_{1}=5` , +and :math:`c_{2}=4.` Noise is added to :math:`y_{i}` and the +coefficients :math:`c_{1}` and :math:`c_{2}` are estimated using +linear least squares. .. plot:: @@ -2170,9 +2259,12 @@ Generalized inverse ^^^^^^^^^^^^^^^^^^^ -The generalized inverse is calculated using the command :obj:`linalg.pinv` or :obj:`linalg.pinv2`. These two commands differ in how they compute the generalized inverse. -The first uses the linalg.lstsq algorithm while the second uses -singular value decomposition. Let :math:`\mathbf{A}` be an :math:`M\times N` matrix, then if :math:`M>N` the generalized inverse is +The generalized inverse is calculated using the command +:obj:`linalg.pinv` or :obj:`linalg.pinv2`. These two commands differ +in how they compute the generalized inverse. The first uses the +linalg.lstsq algorithm while the second uses singular value +decomposition. Let :math:`\mathbf{A}` be an :math:`M\times N` matrix, +then if :math:`M>N` the generalized inverse is .. math:: :nowrap: @@ -2208,26 +2300,27 @@ The eigenvalue-eigenvector problem is one of the most commonly employed linear algebra operations. In one popular form, the -eigenvalue-eigenvector problem is to find for some square matrix :math:`\mathbf{A}` scalars :math:`\lambda` and corresponding vectors :math:`\mathbf{v}` such that +eigenvalue-eigenvector problem is to find for some square matrix +:math:`\mathbf{A}` scalars :math:`\lambda` and corresponding vectors +:math:`\mathbf{v}` such that .. math:: :nowrap: \[ \mathbf{Av}=\lambda\mathbf{v}.\] -For an :math:`N\times N` matrix, there are :math:`N` (not necessarily distinct) eigenvalues --- roots of the -(characteristic) polynomial +For an :math:`N\times N` matrix, there are :math:`N` (not necessarily +distinct) eigenvalues --- roots of the (characteristic) polynomial .. math:: :nowrap: \[ \left|\mathbf{A}-\lambda\mathbf{I}\right|=0.\] +The eigenvectors, :math:`\mathbf{v}` , are also sometimes called right +eigenvectors to distinguish them from another set of left eigenvectors +that satisfy - -The eigenvectors, :math:`\mathbf{v}` , are also sometimes called right eigenvectors to distinguish them -from another set of left eigenvectors that satisfy - .. math:: :nowrap: @@ -2240,7 +2333,10 @@ \[ \mathbf{A}^{H}\mathbf{v}_{L}=\lambda^{*}\mathbf{v}_{L}.\] -With it's default optional arguments, the command :obj:`linalg.eig` returns :math:`\lambda` and :math:`\mathbf{v}.` However, it can also return :math:`\mathbf{v}_{L}` and just :math:`\lambda` by itself ( :obj:`linalg.eigvals` returns just :math:`\lambda` as well). +With it's default optional arguments, the command :obj:`linalg.eig` +returns :math:`\lambda` and :math:`\mathbf{v}.` However, it can also +return :math:`\mathbf{v}_{L}` and just :math:`\lambda` by itself ( +:obj:`linalg.eigvals` returns just :math:`\lambda` as well). In addtion, :obj:`linalg.eig` can also solve the more general eigenvalue problem @@ -2249,20 +2345,25 @@ \begin{eqnarray*} \mathbf{Av} & = & \lambda\mathbf{Bv}\\ \mathbf{A}^{H}\mathbf{v}_{L} & = & \lambda^{*}\mathbf{B}^{H}\mathbf{v}_{L}\end{eqnarray*} -for square matrices :math:`\mathbf{A}` and :math:`\mathbf{B}.` The standard eigenvalue problem is an example of the general -eigenvalue problem for :math:`\mathbf{B}=\mathbf{I}.` When a generalized eigenvalue problem can be solved, then it provides -a decomposition of :math:`\mathbf{A}` as +for square matrices :math:`\mathbf{A}` and :math:`\mathbf{B}.` The +standard eigenvalue problem is an example of the general eigenvalue +problem for :math:`\mathbf{B}=\mathbf{I}.` When a generalized +eigenvalue problem can be solved, then it provides a decomposition of +:math:`\mathbf{A}` as .. math:: :nowrap: \[ \mathbf{A}=\mathbf{BV}\boldsymbol{\Lambda}\mathbf{V}^{-1}\] -where :math:`\mathbf{V}` is the collection of eigenvectors into columns and :math:`\boldsymbol{\Lambda}` is a diagonal matrix of eigenvalues. +where :math:`\mathbf{V}` is the collection of eigenvectors into +columns and :math:`\boldsymbol{\Lambda}` is a diagonal matrix of +eigenvalues. By definition, eigenvectors are only defined up to a constant scale factor. In SciPy, the scaling factor for the eigenvectors is chosen so -that :math:`\left\Vert \mathbf{v}\right\Vert ^{2}=\sum_{i}v_{i}^{2}=1.` +that :math:`\left\Vert \mathbf{v}\right\Vert +^{2}=\sum_{i}v_{i}^{2}=1.` As an example, consider finding the eigenvalues and eigenvectors of the matrix @@ -2315,16 +2416,39 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Singular Value Decompostion (SVD) can be thought of as an extension of -the eigenvalue problem to matrices that are not square. Let :math:`\mathbf{A}` be an :math:`M\times N` matrix with :math:`M` and :math:`N` arbitrary. The matrices :math:`\mathbf{A}^{H}\mathbf{A}` and :math:`\mathbf{A}\mathbf{A}^{H}` are square hermitian matrices [#]_ of size :math:`N\times N` and :math:`M\times M` respectively. It is known that the eigenvalues of square hermitian -matrices are real and non-negative. In addtion, there are at most :math:`\min\left(M,N\right)` identical non-zero eigenvalues of :math:`\mathbf{A}^{H}\mathbf{A}` and :math:`\mathbf{A}\mathbf{A}^{H}.` Define these positive eigenvalues as :math:`\sigma_{i}^{2}.` The square-root of these are called singular values of :math:`\mathbf{A}.` The eigenvectors of :math:`\mathbf{A}^{H}\mathbf{A}` are collected by columns into an :math:`N\times N` unitary [#]_ matrix :math:`\mathbf{V}` while the eigenvectors of :math:`\mathbf{A}\mathbf{A}^{H}` are collected by columns in the unitary matrix :math:`\mathbf{U}` , the singular values are collected in an :math:`M\times N` zero matrix :math:`\mathbf{\boldsymbol{\Sigma}}` with main diagonal entries set to the singular values. Then +the eigenvalue problem to matrices that are not square. Let +:math:`\mathbf{A}` be an :math:`M\times N` matrix with :math:`M` and +:math:`N` arbitrary. The matrices :math:`\mathbf{A}^{H}\mathbf{A}` and +:math:`\mathbf{A}\mathbf{A}^{H}` are square hermitian matrices [#]_ of +size :math:`N\times N` and :math:`M\times M` respectively. It is known +that the eigenvalues of square hermitian matrices are real and +non-negative. In addtion, there are at most +:math:`\min\left(M,N\right)` identical non-zero eigenvalues of +:math:`\mathbf{A}^{H}\mathbf{A}` and :math:`\mathbf{A}\mathbf{A}^{H}.` +Define these positive eigenvalues as :math:`\sigma_{i}^{2}.` The +square-root of these are called singular values of :math:`\mathbf{A}.` +The eigenvectors of :math:`\mathbf{A}^{H}\mathbf{A}` are collected by +columns into an :math:`N\times N` unitary [#]_ matrix +:math:`\mathbf{V}` while the eigenvectors of +:math:`\mathbf{A}\mathbf{A}^{H}` are collected by columns in the +unitary matrix :math:`\mathbf{U}` , the singular values are collected +in an :math:`M\times N` zero matrix +:math:`\mathbf{\boldsymbol{\Sigma}}` with main diagonal entries set to +the singular values. Then .. math:: :nowrap: \[ \mathbf{A=U}\boldsymbol{\Sigma}\mathbf{V}^{H}\] -is the singular-value decomposition of :math:`\mathbf{A}.` Every matrix has a singular value decomposition. Sometimes, the -singular values are called the spectrum of :math:`\mathbf{A}.` The command :obj:`linalg.svd` will return :math:`\mathbf{U}` , :math:`\mathbf{V}^{H}` , and :math:`\sigma_{i}` as an array of the singular values. To obtain the matrix :math:`\mathbf{\Sigma}` use :obj:`linalg.diagsvd`. The following example illustrates the use of :obj:`linalg.svd` . +is the singular-value decomposition of :math:`\mathbf{A}.` Every +matrix has a singular value decomposition. Sometimes, the singular +values are called the spectrum of :math:`\mathbf{A}.` The command +:obj:`linalg.svd` will return :math:`\mathbf{U}` , +:math:`\mathbf{V}^{H}` , and :math:`\sigma_{i}` as an array of the +singular values. To obtain the matrix :math:`\mathbf{\Sigma}` use +:obj:`linalg.diagsvd`. The following example illustrates the use of +:obj:`linalg.svd` . >>> A = mat('[1 3 2; 1 2 3]') >>> M,N = A.shape @@ -2349,7 +2473,7 @@ [[ 1. 3. 2.] [ 1. 2. 3.]] -.. [#] A hermition matrix :math:`\mathbf{D}` satisfies :math:`\mathbf{D}^{H}=\mathbf{D}.` +.. [#] A hermitian matrix :math:`\mathbf{D}` satisfies :math:`\mathbf{D}^{H}=\mathbf{D}.` .. [#] A unitary matrix :math:`\mathbf{D}` satisfies :math:`\mathbf{D}^{H}\mathbf{D}=\mathbf{I}=\mathbf{D}\mathbf{D}^{H}` so that :math:`\mathbf{D}^{-1}=\mathbf{D}^{H}.` @@ -2364,8 +2488,12 @@ \[ \mathbf{A}=\mathbf{PLU}\] -where :math:`\mathbf{P}` is an :math:`M\times M` permutation matrix (a permutation of the rows of the identity matrix), :math:`\mathbf{L}` is in :math:`M\times K` lower triangular or trapezoidal matrix ( :math:`K=\min\left(M,N\right)` ) with unit-diagonal, and :math:`\mathbf{U}` is an upper triangular or trapezoidal matrix. The SciPy command for -this decomposition is :obj:`linalg.lu` . +where :math:`\mathbf{P}` is an :math:`M\times M` permutation matrix (a +permutation of the rows of the identity matrix), :math:`\mathbf{L}` is +in :math:`M\times K` lower triangular or trapezoidal matrix ( +:math:`K=\min\left(M,N\right)` ) with unit-diagonal, and +:math:`\mathbf{U}` is an upper triangular or trapezoidal matrix. The +SciPy command for this decomposition is :obj:`linalg.lu` . Such a decomposition is often useful for solving many simultaneous equations where the left-hand-side does not change but the right hand @@ -2383,32 +2511,48 @@ \[ \mathbf{PLUx}_{i}=\mathbf{b}_{i}.\] -Because :math:`\mathbf{L}` is lower-triangular, the equation can be solved for :math:`\mathbf{U}\mathbf{x}_{i}` and finally :math:`\mathbf{x}_{i}` very rapidly using forward- and back-substitution. An initial time -spent factoring :math:`\mathbf{A}` allows for very rapid solution of similar systems of equations in the +Because :math:`\mathbf{L}` is lower-triangular, the equation can be +solved for :math:`\mathbf{U}\mathbf{x}_{i}` and finally +:math:`\mathbf{x}_{i}` very rapidly using forward- and +back-substitution. An initial time spent factoring :math:`\mathbf{A}` +allows for very rapid solution of similar systems of equations in the future. If the intent for performing LU decomposition is for solving -linear systems then the command :obj:`linalg.lu_factor` should be used followed by repeated applications of the command :obj:`linalg.lu_solve` to solve the system for each new right-hand-side. +linear systems then the command :obj:`linalg.lu_factor` should be used +followed by repeated applications of the command +:obj:`linalg.lu_solve` to solve the system for each new +right-hand-side. Cholesky decomposition ^^^^^^^^^^^^^^^^^^^^^^ Cholesky decomposition is a special case of LU decomposition -applicable to Hermitian positive definite matrices. When :math:`\mathbf{A}=\mathbf{A}^{H}` and :math:`\mathbf{x}^{H}\mathbf{Ax}\geq0` for all :math:`\mathbf{x}` , then decompositions of :math:`\mathbf{A}` can be found so that +applicable to Hermitian positive definite matrices. When +:math:`\mathbf{A}=\mathbf{A}^{H}` and +:math:`\mathbf{x}^{H}\mathbf{Ax}\geq0` for all :math:`\mathbf{x}` , +then decompositions of :math:`\mathbf{A}` can be found so that .. math:: :nowrap: \begin{eqnarray*} \mathbf{A} & = & \mathbf{U}^{H}\mathbf{U}\\ \mathbf{A} & = & \mathbf{L}\mathbf{L}^{H}\end{eqnarray*} -where :math:`\mathbf{L}` is lower-triangular and :math:`\mathbf{U}` is upper triangular. Notice that :math:`\mathbf{L}=\mathbf{U}^{H}.` The command :obj:`linagl.cholesky` computes the cholesky factorization. For using cholesky factorization -to solve systems of equations there are also :obj:`linalg.cho_factor` and :obj:`linalg.cho_solve` routines that work similarly to their LU decomposition counterparts. +where :math:`\mathbf{L}` is lower-triangular and :math:`\mathbf{U}` is +upper triangular. Notice that :math:`\mathbf{L}=\mathbf{U}^{H}.` The +command :obj:`linagl.cholesky` computes the cholesky +factorization. For using cholesky factorization to solve systems of +equations there are also :obj:`linalg.cho_factor` and +:obj:`linalg.cho_solve` routines that work similarly to their LU +decomposition counterparts. QR decomposition ^^^^^^^^^^^^^^^^ The QR decomposition (sometimes called a polar decomposition) works -for any :math:`M\times N` array and finds an :math:`M\times M` unitary matrix :math:`\mathbf{Q}` and an :math:`M\times N` upper-trapezoidal matrix :math:`\mathbf{R}` such that +for any :math:`M\times N` array and finds an :math:`M\times M` unitary +matrix :math:`\mathbf{Q}` and an :math:`M\times N` upper-trapezoidal +matrix :math:`\mathbf{R}` such that .. math:: :nowrap: @@ -2422,26 +2566,37 @@ \[ \mathbf{A}=\mathbf{U}\boldsymbol{\Sigma}\mathbf{V}^{H}=\mathbf{QR}\] -implies that :math:`\mathbf{Q}=\mathbf{U}` and :math:`\mathbf{R}=\boldsymbol{\Sigma}\mathbf{V}^{H}.` Note, however, that in SciPy independent algorithms are used to find -QR and SVD decompositions. The command for QR decomposition is :obj:`linalg.qr` . +implies that :math:`\mathbf{Q}=\mathbf{U}` and +:math:`\mathbf{R}=\boldsymbol{\Sigma}\mathbf{V}^{H}.` Note, however, +that in SciPy independent algorithms are used to find QR and SVD +decompositions. The command for QR decomposition is :obj:`linalg.qr` . Schur decomposition ^^^^^^^^^^^^^^^^^^^ -For a square :math:`N\times N` matrix, :math:`\mathbf{A}` , the Schur decomposition finds (not-necessarily unique) matrices :math:`\mathbf{T}` and :math:`\mathbf{Z}` such that +For a square :math:`N\times N` matrix, :math:`\mathbf{A}` , the Schur +decomposition finds (not-necessarily unique) matrices +:math:`\mathbf{T}` and :math:`\mathbf{Z}` such that .. math:: :nowrap: \[ \mathbf{A}=\mathbf{ZT}\mathbf{Z}^{H}\] -where :math:`\mathbf{Z}` is a unitary matrix and :math:`\mathbf{T}` is either upper-triangular or quasi-upper triangular depending on -whether or not a real schur form or complex schur form is requested. -For a real schur form both :math:`\mathbf{T}` and :math:`\mathbf{Z}` are real-valued when :math:`\mathbf{A}` is real-valued. When :math:`\mathbf{A}` is a real-valued matrix the real schur form is only quasi-upper -triangular because :math:`2\times2` blocks extrude from the main diagonal corresponding to any complex- -valued eigenvalues. The command :obj:`linalg.schur` finds the Schur decomposition while the command :obj:`linalg.rsf2csf` converts :math:`\mathbf{T}` and :math:`\mathbf{Z}` from a real Schur form to a complex Schur form. The Schur form is -especially useful in calculating functions of matrices. +where :math:`\mathbf{Z}` is a unitary matrix and :math:`\mathbf{T}` is +either upper-triangular or quasi-upper triangular depending on whether +or not a real schur form or complex schur form is requested. For a +real schur form both :math:`\mathbf{T}` and :math:`\mathbf{Z}` are +real-valued when :math:`\mathbf{A}` is real-valued. When +:math:`\mathbf{A}` is a real-valued matrix the real schur form is only +quasi-upper triangular because :math:`2\times2` blocks extrude from +the main diagonal corresponding to any complex- valued +eigenvalues. The command :obj:`linalg.schur` finds the Schur +decomposition while the command :obj:`linalg.rsf2csf` converts +:math:`\mathbf{T}` and :math:`\mathbf{Z}` from a real Schur form to a +complex Schur form. The Schur form is especially useful in calculating +functions of matrices. The following example illustrates the schur decomposition: @@ -2537,7 +2692,8 @@ where the matrix exponential of the diagonal matrix :math:`\boldsymbol{\Lambda}` is just the exponential of its elements. This method is implemented in :obj:`linalg.expm2` . The preferred method for implementing the matrix exponential is to use -scaling and a Pad? approximation for :math:`e^{x}` . This algorithm is implemented as :obj:`linalg.expm` . +scaling and a Pad? approximation for :math:`e^{x}` . This algorithm is +implemented as :obj:`linalg.expm` . The inverse of the matrix exponential is the matrix logarithm defined as the inverse of the matrix exponential. @@ -2583,14 +2739,17 @@ Hyperbolic trigonometric functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The hyperbolic trigonemetric functions :math:`\sinh` , :math:`\cosh` , and :math:`\tanh` can also be defined for matrices using the familiar definitions: +The hyperbolic trigonemetric functions :math:`\sinh` , :math:`\cosh` , +and :math:`\tanh` can also be defined for matrices using the familiar +definitions: .. math:: :nowrap: \begin{eqnarray*} \sinh\left(\mathbf{A}\right) & = & \frac{e^{\mathbf{A}}-e^{-\mathbf{A}}}{2}\\ \cosh\left(\mathbf{A}\right) & = & \frac{e^{\mathbf{A}}+e^{-\mathbf{A}}}{2}\\ \tanh\left(\mathbf{A}\right) & = & \left[\cosh\left(\mathbf{A}\right)\right]^{-1}\sinh\left(\mathbf{A}\right).\end{eqnarray*} -These matrix functions can be found using :obj:`linalg.sinhm` , :obj:`linalg.coshm` , and :obj:`linalg.tanhm` . +These matrix functions can be found using :obj:`linalg.sinhm`, +:obj:`linalg.coshm` , and :obj:`linalg.tanhm`. Arbitrary function @@ -2608,7 +2767,7 @@ >>> from scipy import special, random, linalg >>> A = random.rand(3,3) - >>> B = linalg.funm(A,lambda x: special.jv(0,real(x))) + >>> B = linalg.funm(A,lambda x: special.jv(0,x)) >>> print A [[ 0.72578091 0.34105276 0.79570345] [ 0.65767207 0.73855618 0.541453 ] @@ -2624,7 +2783,10 @@ >>> print linalg.eigvals(B) [ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] +Note how, by virtue of how matrix analytic functions are defined, +the Bessel function has acted on the matrix eigenvalues. + Statistics ========== @@ -2647,32 +2809,34 @@ files continuous.lyx and discrete.lyx in the stats sub-directories. -Interfacing with Python Imaging Library -======================================= - -If you have the Python Imaging Library installed, SciPy provides some -convenient functions that make use of it's facilities particularly for -reading, writing, displaying, and rotating images. In SciPy an image -is always a two- or three-dimensional array. Gray-scale, and colormap -images are always two-dimensional arrays while RGB images are three- -dimensional with the third dimension specifying the channel. - -Commands available include - -- fromimage --- convert a PIL image to a Numpy array - -- toimage --- convert Numpy array to PIL image - -- imsave --- save Numpy array to an image file - -- imread --- read an image file into a Numpy array - -- imrotate --- rotate an image (a Numpy array) counter-clockwise - -- imresize --- resize an image using the PIL - -- imshow --- external viewer of a Numpy array (using PIL) - -- imfilter --- fast, simple built-in filters provided by PIL - -- radon --- simple radon transform based on imrotate +.. XXX: is this up-to-date? +.. +.. Interfacing with Python Imaging Library +.. ======================================= +.. +.. If you have the Python Imaging Library installed, SciPy provides some +.. convenient functions that make use of it's facilities particularly for +.. reading, writing, displaying, and rotating images. In SciPy an image +.. is always a two- or three-dimensional array. Gray-scale, and colormap +.. images are always two-dimensional arrays while RGB images are three- +.. dimensional with the third dimension specifying the channel. +.. +.. Commands available include +.. +.. - fromimage --- convert a PIL image to a Numpy array +.. +.. - toimage --- convert Numpy array to PIL image +.. +.. - imsave --- save Numpy array to an image file +.. +.. - imread --- read an image file into a Numpy array +.. +.. - imrotate --- rotate an image (a Numpy array) counter-clockwise +.. +.. - imresize --- resize an image using the PIL +.. +.. - imshow --- external viewer of a Numpy array (using PIL) +.. +.. - imfilter --- fast, simple built-in filters provided by PIL +.. +.. - radon --- simple radon transform based on imrotate From scipy-svn at scipy.org Wed Dec 3 21:50:53 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 3 Dec 2008 20:50:53 -0600 (CST) Subject: [Scipy-svn] r5217 - trunk/tools/win32/build_scripts/nsis_scripts Message-ID: <20081204025053.73DD3C7C009@scipy.org> Author: cdavid Date: 2008-12-03 20:50:45 -0600 (Wed, 03 Dec 2008) New Revision: 5217 Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in Log: Fix CRLF in nsis installer script template. Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in =================================================================== --- trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-03 23:24:44 UTC (rev 5216) +++ trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 02:50:45 UTC (rev 5217) @@ -1,121 +1,121 @@ -;-------------------------------- -;Include Modern UI - -!include "MUI2.nsh" - -SetCompress off ; Useful to disable compression under development -;SetCompressor /Solid LZMA ; Useful to disable compression under development - -;-------------------------------- -;General - -;Name and file -Name "Scipy super installer" -OutFile "@SCIPY_INSTALLER_NAME@" - -;Default installation folder -InstallDir "$TEMP" - -;-------------------------------- -;Interface Settings - -!define MUI_ABORTWARNING - -;-------------------------------- -;Pages - -;!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt" -;!insertmacro MUI_PAGE_COMPONENTS -;!insertmacro MUI_PAGE_DIRECTORY -;!insertmacro MUI_PAGE_INSTFILES - -;!insertmacro MUI_UNPAGE_CONFIRM -;!insertmacro MUI_UNPAGE_INSTFILES - -;-------------------------------- -;Languages - -!insertmacro MUI_LANGUAGE "English" - -;-------------------------------- -;Component Sections - -!include 'Sections.nsh' -!include LogicLib.nsh - -Var HasSSE2 -Var HasSSE3 -Var CPUSSE - -Section "Core" SecCore - - ;SectionIn RO - SetOutPath "$INSTDIR" - - ;Create uninstaller - ;WriteUninstaller "$INSTDIR\Uninstall.exe" - - DetailPrint "Install dir for actual installers is $INSTDIR" - - StrCpy $CPUSSE "0" - CpuCaps::hasSSE2 - Pop $0 - StrCpy $HasSSE2 $0 - - CpuCaps::hasSSE3 - Pop $0 - StrCpy $HasSSE3 $0 - - ; Debug - StrCmp $HasSSE2 "Y" include_sse2 no_include_sse2 - include_sse2: - DetailPrint '"Target CPU handles SSE2"' - StrCpy $CPUSSE "2" - goto done_sse2 - no_include_sse2: - DetailPrint '"Target CPU does NOT handle SSE2"' - goto done_sse2 - done_sse2: - - StrCmp $HasSSE3 "Y" include_sse3 no_include_sse3 - include_sse3: - DetailPrint '"Target CPU handles SSE3"' - StrCpy $CPUSSE "3" - goto done_sse3 - no_include_sse3: - DetailPrint '"Target CPU does NOT handle SSE3"' - goto done_sse3 - done_sse3: - - ClearErrors - - ; Install files conditionaly on detected cpu - ${Switch} $CPUSSE - ${Case} "3" - DetailPrint '"Install SSE 3"' - File "binaries\@SSE3_BINARY@" - ExecWait '"$INSTDIR\@SSE3_BINARY@"' - ${Break} - ${Case} "2" - DetailPrint '"Install SSE 2"' - File "binaries\@SSE2_BINARY@" - ExecWait '"$INSTDIR\@SSE2_BINARY@"' - ${Break} - ${Default} - DetailPrint '"Install NO SSE"' - File "binaries\@NOSSE_BINARY@" - ExecWait '"$INSTDIR\@NOSSE_BINARY@"' - ${Break} - ${EndSwitch} - - ; Handle errors when executing installers - IfErrors error no_error - - error: - messageBox MB_OK "Executing scipy installer failed" - goto done - no_error: - goto done - done: - -SectionEnd +;-------------------------------- +;Include Modern UI + +!include "MUI2.nsh" + +SetCompress off ; Useful to disable compression under development +;SetCompressor /Solid LZMA ; Useful to disable compression under development + +;-------------------------------- +;General + +;Name and file +Name "Scipy super installer" +OutFile "@SCIPY_INSTALLER_NAME@" + +;Default installation folder +InstallDir "$TEMP" + +;-------------------------------- +;Interface Settings + +!define MUI_ABORTWARNING + +;-------------------------------- +;Pages + +;!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt" +;!insertmacro MUI_PAGE_COMPONENTS +;!insertmacro MUI_PAGE_DIRECTORY +;!insertmacro MUI_PAGE_INSTFILES + +;!insertmacro MUI_UNPAGE_CONFIRM +;!insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + +!insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Component Sections + +!include 'Sections.nsh' +!include LogicLib.nsh + +Var HasSSE2 +Var HasSSE3 +Var CPUSSE + +Section "Core" SecCore + + ;SectionIn RO + SetOutPath "$INSTDIR" + + ;Create uninstaller + ;WriteUninstaller "$INSTDIR\Uninstall.exe" + + DetailPrint "Install dir for actual installers is $INSTDIR" + + StrCpy $CPUSSE "0" + CpuCaps::hasSSE2 + Pop $0 + StrCpy $HasSSE2 $0 + + CpuCaps::hasSSE3 + Pop $0 + StrCpy $HasSSE3 $0 + + ; Debug + StrCmp $HasSSE2 "Y" include_sse2 no_include_sse2 + include_sse2: + DetailPrint '"Target CPU handles SSE2"' + StrCpy $CPUSSE "2" + goto done_sse2 + no_include_sse2: + DetailPrint '"Target CPU does NOT handle SSE2"' + goto done_sse2 + done_sse2: + + StrCmp $HasSSE3 "Y" include_sse3 no_include_sse3 + include_sse3: + DetailPrint '"Target CPU handles SSE3"' + StrCpy $CPUSSE "3" + goto done_sse3 + no_include_sse3: + DetailPrint '"Target CPU does NOT handle SSE3"' + goto done_sse3 + done_sse3: + + ClearErrors + + ; Install files conditionaly on detected cpu + ${Switch} $CPUSSE + ${Case} "3" + DetailPrint '"Install SSE 3"' + File "binaries\@SSE3_BINARY@" + ExecWait '"$INSTDIR\@SSE3_BINARY@"' + ${Break} + ${Case} "2" + DetailPrint '"Install SSE 2"' + File "binaries\@SSE2_BINARY@" + ExecWait '"$INSTDIR\@SSE2_BINARY@"' + ${Break} + ${Default} + DetailPrint '"Install NO SSE"' + File "binaries\@NOSSE_BINARY@" + ExecWait '"$INSTDIR\@NOSSE_BINARY@"' + ${Break} + ${EndSwitch} + + ; Handle errors when executing installers + IfErrors error no_error + + error: + messageBox MB_OK "Executing scipy installer failed" + goto done + no_error: + goto done + done: + +SectionEnd From scipy-svn at scipy.org Wed Dec 3 21:51:11 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 3 Dec 2008 20:51:11 -0600 (CST) Subject: [Scipy-svn] r5218 - trunk/tools/win32/build_scripts/nsis_scripts Message-ID: <20081204025111.507DDC7C009@scipy.org> Author: cdavid Date: 2008-12-03 20:51:06 -0600 (Wed, 03 Dec 2008) New Revision: 5218 Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in Log: Start working on command line argument to force an arch. Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in =================================================================== --- trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 02:50:45 UTC (rev 5217) +++ trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 02:51:06 UTC (rev 5218) @@ -3,6 +3,11 @@ !include "MUI2.nsh" +; Include FileFunc for command line parsing options +!include "FileFunc.nsh" +!insertmacro GetParameters +!insertmacro GetOptions + SetCompress off ; Useful to disable compression under development ;SetCompressor /Solid LZMA ; Useful to disable compression under development @@ -46,7 +51,35 @@ Var HasSSE2 Var HasSSE3 Var CPUSSE +Var option_arch +Function .onInit + ; Get parameters + var /GLOBAL cmdLineParams + Push $R0 + + ${GetParameters} $cmdLineParams + + ; XXX; How to get a console output help ? GUI seems useless when using + ; command line help... + ; ; /? param (help) + ; ClearErrors + ; ${GetOptions} $cmdLineParams '/?' $R0 + ; IfErrors +3 0 + ; MessageBox MB_OK "list all command line options here!" + ; Abort + + Pop $R0 + + ; Initialise options + StrCpy $option_arch 'native' + + ; Parse Parameters + Push $R0 + Call parseParameters + Pop $R0 +FunctionEnd + Section "Core" SecCore ;SectionIn RO @@ -89,6 +122,18 @@ ClearErrors + ${Switch} $option_arch + ${Case} "native" + DetailPrint '"arch value: $option_arch - native install"' + ${Break} + ${Case} "nosse" + DetailPrint '"arch value: $option_arch - no-sse install"' + ${Break} + ${Default} + DetailPrint '"No option_arch value - native install, do not override detection"' + ${Break} + ${EndSwitch} + ; Install files conditionaly on detected cpu ${Switch} $CPUSSE ${Case} "3" @@ -119,3 +164,10 @@ done: SectionEnd + +Function parseParameters + ; /arch option + ${GetOptions} $cmdLineParams '/arch' $R0 + IfErrors +2 0 + StrCpy $option_arch $R0 +FunctionEnd From scipy-svn at scipy.org Wed Dec 3 21:56:37 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 3 Dec 2008 20:56:37 -0600 (CST) Subject: [Scipy-svn] r5219 - trunk/tools/win32/build_scripts/nsis_scripts Message-ID: <20081204025637.89D37C7C009@scipy.org> Author: cdavid Date: 2008-12-03 20:56:33 -0600 (Wed, 03 Dec 2008) New Revision: 5219 Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in Log: Support all possible arch from the command line (parsing only). Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in =================================================================== --- trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 02:51:06 UTC (rev 5218) +++ trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 02:56:33 UTC (rev 5219) @@ -124,13 +124,21 @@ ${Switch} $option_arch ${Case} "native" - DetailPrint '"arch value: $option_arch - native install"' + DetailPrint '"native install (arch value: $option_arch)"' ${Break} ${Case} "nosse" - DetailPrint '"arch value: $option_arch - no-sse install"' + DetailPrint '"nosse install (arch value: $option_arch)"' ${Break} + ${Case} "sse2" + DetailPrint '"sse2 install (arch value: $option_arch)"' + ${Break} + ${Case} "sse3" + DetailPrint '"sse3 install (arch value: $option_arch)"' + ${Break} ${Default} - DetailPrint '"No option_arch value - native install, do not override detection"' + MessageBox MB_OK "option /arch $option_arch not understood: " + "only native, nosse, sse2 and sse3 are valid." + Abort ${Break} ${EndSwitch} From scipy-svn at scipy.org Wed Dec 3 22:01:09 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 3 Dec 2008 21:01:09 -0600 (CST) Subject: [Scipy-svn] r5220 - trunk/tools/win32/build_scripts/nsis_scripts Message-ID: <20081204030109.D9D16C7C009@scipy.org> Author: cdavid Date: 2008-12-03 21:01:05 -0600 (Wed, 03 Dec 2008) New Revision: 5220 Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in Log: Fix bogus line continuation. Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in =================================================================== --- trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 02:56:33 UTC (rev 5219) +++ trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 03:01:05 UTC (rev 5220) @@ -136,8 +136,7 @@ DetailPrint '"sse3 install (arch value: $option_arch)"' ${Break} ${Default} - MessageBox MB_OK "option /arch $option_arch not understood: " - "only native, nosse, sse2 and sse3 are valid." + MessageBox MB_OK "option /arch $option_arch not understood: only native, nosse, sse2 and sse3 are valid." Abort ${Break} ${EndSwitch} From scipy-svn at scipy.org Wed Dec 3 22:01:24 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 3 Dec 2008 21:01:24 -0600 (CST) Subject: [Scipy-svn] r5221 - trunk/tools/win32/build_scripts/nsis_scripts Message-ID: <20081204030124.1A51BC7C009@scipy.org> Author: cdavid Date: 2008-12-03 21:01:21 -0600 (Wed, 03 Dec 2008) New Revision: 5221 Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in Log: Override detected arch with /arch option if given. Modified: trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in =================================================================== --- trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 03:01:05 UTC (rev 5220) +++ trunk/tools/win32/build_scripts/nsis_scripts/scipy-superinstaller.nsi.in 2008-12-04 03:01:21 UTC (rev 5221) @@ -128,12 +128,15 @@ ${Break} ${Case} "nosse" DetailPrint '"nosse install (arch value: $option_arch)"' + StrCpy $CPUSSE "0" ${Break} ${Case} "sse2" DetailPrint '"sse2 install (arch value: $option_arch)"' + StrCpy $CPUSSE "2" ${Break} ${Case} "sse3" DetailPrint '"sse3 install (arch value: $option_arch)"' + StrCpy $CPUSSE "3" ${Break} ${Default} MessageBox MB_OK "option /arch $option_arch not understood: only native, nosse, sse2 and sse3 are valid." From scipy-svn at scipy.org Thu Dec 4 17:49:41 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 4 Dec 2008 16:49:41 -0600 (CST) Subject: [Scipy-svn] r5222 - trunk/scipy/stats Message-ID: <20081204224941.6CECCC7C00B@scipy.org> Author: josef Date: 2008-12-04 16:49:32 -0600 (Thu, 04 Dec 2008) New Revision: 5222 Modified: trunk/scipy/stats/stats.py Log: some import cleanup Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-04 03:01:21 UTC (rev 5221) +++ trunk/scipy/stats/stats.py 2008-12-04 22:49:32 UTC (rev 5222) @@ -199,6 +199,10 @@ import scipy.linalg as linalg import numpy as np +#import scipy.stats #is this a circular import ? +from morestats import find_repeats #is only reference to scipy.stats +import distributions + # Local imports. import _support @@ -1993,6 +1997,8 @@ Examples -------- + >>> from scipy import stats + >>> import numpy as np >>> x = np.linspace(-15,15,9) >>> kstest(x,'norm') (0.44435602715924361, 0.038850142705171065) @@ -2262,7 +2268,7 @@ # Handle ties ties = 0 for i in range(len(data)): - replist, repnum = scipy.stats.find_repeats(array(data[i])) + replist, repnum = find_repeats(array(data[i])) for t in repnum: ties += t*(t*t-1) c = 1 - ties / float(k*(k*k-1)*n) From scipy-svn at scipy.org Thu Dec 4 17:53:44 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 4 Dec 2008 16:53:44 -0600 (CST) Subject: [Scipy-svn] r5223 - in trunk/scipy/stats: . tests Message-ID: <20081204225344.2E4A5C7C00B@scipy.org> Author: josef Date: 2008-12-04 16:53:40 -0600 (Thu, 04 Dec 2008) New Revision: 5223 Modified: trunk/scipy/stats/stats.py trunk/scipy/stats/tests/test_stats.py Log: new version of ks2_samp without NR, with tests Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-04 22:49:32 UTC (rev 5222) +++ trunk/scipy/stats/stats.py 2008-12-04 22:53:40 UTC (rev 5223) @@ -2094,39 +2094,71 @@ def ks_2samp(data1, data2): - """ Computes the Kolmogorov-Smirnof statistic on 2 samples. Modified - from Numerical Recipies in C, page 493. Returns KS D-value, prob. Not - ufunc- like. + """ Computes the Kolmogorov-Smirnof statistic on 2 samples. + data1, data2: array_like, 1-dim + samples assumed to be drawn from a continuous distribution, + sample sizes can be different + Returns: KS D-value, p-value + + Description: + ------------ + + Tests whether 2 samples are drawn from the same distribution. Note + that, like the one-sample K-S test the distribution is assumed to be + continuous. + + This is the two-sided test, one-sided tests are not implemented. + The test uses the two-sided asymptotic Kolmogorov-Smirnov distribution. + + If the K-S statistic is small or the p-value is high, then we cannot + reject the hypothesis that the two distributions of the two samples + are the same + + Examples: + --------- + + >>> np.random.seed(12345678); + + >>> n1 = 200 # size of first sample + >>> n2 = 300 # size of second sample + + # different distribution + we can reject the null hypothesis since the pvalue is below 1% + >>> rvs1 = stats.norm.rvs(size=n1,loc=0.,scale=1); + >>> rvs2 = stats.norm.rvs(size=n2,loc=0.5,scale=1.5) + >>> ks_2samp_new(rvs1,rvs2) + (0.17333333333333334, 0.0012436147919875644) + + slightly different distribution + we cannot reject the null hypothesis since the pvalue is high, 43.8% + >>> rvs3 = stats.norm.rvs(size=n2,loc=0.01,scale=1.0) + >>> ks_2samp_new(rvs1,rvs3) + (0.078333333333333255, 0.4379740175003739) + + identical distribution + we cannot reject the null hypothesis since the pvalue is high, 65% + >>> rvs4 = stats.norm.rvs(size=n2,loc=0.0,scale=1.0) + >>> ks_2samp_new(rvs1,rvs4) + (0.066666666666666652, 0.64576306820960394) + """ data1, data2 = map(asarray, (data1, data2)) - j1 = 0 # zeros(data1.shape[1:]) TRIED TO MAKE THIS UFUNC-LIKE - j2 = 0 # zeros(data2.shape[1:]) - fn1 = 0.0 # zeros(data1.shape[1:],float) - fn2 = 0.0 # zeros(data2.shape[1:],float) n1 = data1.shape[0] n2 = data2.shape[0] - en1 = n1*1 - en2 = n2*1 - d = zeros(data1.shape[1:]) - data1 = np.sort(data1,0) - data2 = np.sort(data2,0) - while j1 < n1 and j2 < n2: - d1=data1[j1] - d2=data2[j2] - if d1 <= d2: - fn1 = (j1)/float(en1) - j1 = j1 + 1 - if d2 <= d1: - fn2 = (j2)/float(en2) - j2 = j2 + 1 - dt = (fn2-fn1) - if abs(dt) > abs(d): - d = dt + n1 = len(data1) + n2 = len(data2) + data1 = np.sort(data1) + data2 = np.sort(data2) + data_all = np.concatenate([data1,data2]) + cdf1 = np.searchsorted(data1,data_all,side='right')/(1.0*n1) + cdf2 = (np.searchsorted(data2,data_all,side='right'))/(1.0*n2) + d = np.max(np.absolute(cdf1-cdf2)) + #Note: d absolute not signed distance + en = np.sqrt(n1*n2/float(n1+n2)) try: - en = np.sqrt(en1*en2/float(en1+en2)) - prob = ksprob((en+0.12+0.11/en)*np.fabs(d)) + prob = ksprob((en+0.12+0.11/en)*d) except: prob = 1.0 return d, prob Modified: trunk/scipy/stats/tests/test_stats.py =================================================================== --- trunk/scipy/stats/tests/test_stats.py 2008-12-04 22:49:32 UTC (rev 5222) +++ trunk/scipy/stats/tests/test_stats.py 2008-12-04 22:53:40 UTC (rev 5223) @@ -1024,5 +1024,35 @@ assert_almost_equal( np.array(stats.kstest(x,'norm', alternative = 'larger')), np.array((0.0072115233216310994, 0.98531158590396228)), 14) + #missing: no test that uses *args + + +def test_ks_2samp(): + #exact small sample solution + data1 = np.array([1.0,2.0]) + data2 = np.array([1.0,2.0,3.0]) + assert_almost_equal(np.array(stats.ks_2samp(data1+0.01,data2)), + np.array((0.33333333333333337, 0.99062316386915694))) + assert_almost_equal(np.array(stats.ks_2samp(data1-0.01,data2)), + np.array((0.66666666666666674, 0.42490954988801982))) + #these can also be verified graphically + assert_almost_equal( + np.array(stats.ks_2samp(np.linspace(1,100,100), + np.linspace(1,100,100)+2+0.1)), + np.array((0.030000000000000027, 0.99999999996005062))) + assert_almost_equal( + np.array(stats.ks_2samp(np.linspace(1,100,100), + np.linspace(1,100,100)+2-0.1)), + np.array((0.020000000000000018, 0.99999999999999933))) + #these are just regression tests + assert_almost_equal( + np.array(stats.ks_2samp(np.linspace(1,100,100), + np.linspace(1,100,110)+20.1)), + np.array((0.21090909090909091, 0.015880386730710221))) + assert_almost_equal( + np.array(stats.ks_2samp(np.linspace(1,100,100), + np.linspace(1,100,110)+20-0.1)), + np.array((0.20818181818181825, 0.017981441789762638))) + if __name__ == "__main__": run_module_suite() From scipy-svn at scipy.org Thu Dec 4 18:00:32 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 4 Dec 2008 17:00:32 -0600 (CST) Subject: [Scipy-svn] r5224 - trunk/scipy/stats Message-ID: <20081204230032.32AEBC7C00E@scipy.org> Author: josef Date: 2008-12-04 17:00:30 -0600 (Thu, 04 Dec 2008) New Revision: 5224 Modified: trunk/scipy/stats/stats.py Log: change 3 Student t-tests to use t distribution instead of betainv, tested with doc tests, changes in p-value smaller than 1e-13 add to doc strings Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-04 22:53:40 UTC (rev 5223) +++ trunk/scipy/stats/stats.py 2008-12-04 23:00:30 UTC (rev 5224) @@ -1884,7 +1884,8 @@ df = n-1 svar = ((n-1)*v) / float(df) t = (x-popmean)/np.sqrt(svar*(1.0/n)) - prob = betai(0.5*df,0.5,df/(df+t*t)) + #prob = betai(0.5*df,0.5,df/(df+t*t)) + prob = distributions.t.sf(np.abs(t),df)*2 #use np.abs to get upper tail return t,prob @@ -1895,6 +1896,43 @@ array first), or an integer (the axis over which to operate on a and b). Returns: t-value, two-tailed p-value + + This is a two-sided test for the null hypothesis that 2 independent samples + have identical average (expected) values. + + Description: + ------------ + + We can use this test, if we observe two independent samples from + the same or different population, e.g. exam scores of boys and + girls or of two ethnic groups. The test measures whether the + average (expected) value differs significantly across samples. If + we observe a larger p-value, for example >0.5 or 0.1 then we + cannot reject the null hypothesis of identical average scores. If + the test statistic is larger (in absolute terms than critical + value or, equivalently, if the p-value is smaller than the + threshold, 1%,5% or 10%, then we reject the null hypothesis equal + averages. + + see: http://en.wikipedia.org/wiki/T-test#Independent_two-sample_t-test + + Examples: + --------- + + (note: after changes difference in 13th decimal) + + >>> np.random.seed(12345678) #fix seed to get the same result + + test with sample with identical means + >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) + >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) + >>> stats.ttest_ind(rvs1,rvs2) + (array(0.26833823296239279), 0.78849443369561645) + + test with sample with different means + >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) + >>> stats.ttest_ind(rvs1,rvs3) + (array(-5.0434013458585092), 5.4302979475463849e-007) """ a, b, axis = _chk2_asarray(a, b, axis) x1 = mean(a,axis) @@ -1908,7 +1946,8 @@ zerodivproblem = svar == 0 t = (x1-x2)/np.sqrt(svar*(1.0/n1 + 1.0/n2)) # N-D COMPUTATION HERE!!!!!! t = np.where(zerodivproblem, 1.0, t) # replace NaN t-values with 1.0 - probs = betai(0.5*df,0.5,float(df)/(df+t*t)) + #probs = betai(0.5*df,0.5,float(df)/(df+t*t)) + probs = distributions.t.sf(np.abs(t),df)*2 if not np.isscalar(t): probs = probs.reshape(t.shape) @@ -1923,6 +1962,41 @@ first), or an integer (the axis over which to operate on a and b). Returns: t-value, two-tailed p-value + + Description: + ============ + + This is a two-sided test for the null hypothesis that 2 repeated samples + have identical average values. + + Examples for the use are scores of a student in different exams, + or repeated sampling from the same units. The test measures + whether the average score differs significantly across samples + (e.g. exams). If we observe a larger p-value, for example >0.5 or + 0.1 then we cannot reject the null hypothesis of identical average + scores. If the test statistic is larger (in absolute terms than + critical value or, equivalently, if the p-value is smaller than + the threshold, 1%,5% or 10%, then we reject the null hypothesis + equal averages. + + see: http://en.wikipedia.org/wiki/T-test#Dependent_t-test + + Examples: + ========= + + (note: after changes difference in 13th decimal) + + >>> np.random.seed(12345678) #fix seed to get the same result + >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) + >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) + \ + stats.norm.rvs(scale=0.2,size=500) + >>> stats.ttest_rel(rvs1,rvs2) + (array(0.24101764965300965), 0.80964043445809664) + >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) + \ + stats.norm.rvs(scale=0.2,size=500) + >>> stats.ttest_rel(rvs1,rvs3) + (array(-3.9995108708727929), 7.308240219165646e-005) + """ a, b, axis = _chk2_asarray(a, b, axis) if len(a)!=len(b): @@ -1935,12 +2009,14 @@ df = float(n-1) d = (a-b).astype('d') + #denom is just var(d)/df denom = np.sqrt((n*np.add.reduce(d*d,axis) - np.add.reduce(d,axis)**2) /df) zerodivproblem = denom == 0 t = np.add.reduce(d, axis) / denom # N-D COMPUTATION HERE!!!!!! t = np.where(zerodivproblem, 1.0, t) # replace NaN t-values with 1.0 t = np.where(zerodivproblem, 1.0, t) # replace NaN t-values with 1.0 - probs = betai(0.5*df,0.5,float(df)/(df+t*t)) + #probs = betai(0.5*df,0.5,float(df)/(df+t*t)) + probs = distributions.t.sf(np.abs(t),df)*2 if not np.isscalar(t): probs = np.reshape(probs, t.shape) if not np.isscalar(probs) and len(probs) == 1: @@ -1948,8 +2024,8 @@ return t, probs -import scipy.stats -import distributions +#import scipy.stats +#import distributions def kstest(rvs, cdf, args=(), N=20, alternative = 'unequal', mode='approx'): """Return the D-value and the p-value for a Kolmogorov-Smirnov test From scipy-svn at scipy.org Thu Dec 4 18:11:28 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 4 Dec 2008 17:11:28 -0600 (CST) Subject: [Scipy-svn] r5225 - trunk/scipy/stats Message-ID: <20081204231128.1E669C7C00B@scipy.org> Author: josef Date: 2008-12-04 17:11:25 -0600 (Thu, 04 Dec 2008) New Revision: 5225 Modified: trunk/scipy/stats/__init__.py Log: remove vonmises_cython from __all__, prevents exposing np to np.lookfor as vonmises_cython.np Modified: trunk/scipy/stats/__init__.py =================================================================== --- trunk/scipy/stats/__init__.py 2008-12-04 23:00:30 UTC (rev 5224) +++ trunk/scipy/stats/__init__.py 2008-12-04 23:11:25 UTC (rev 5225) @@ -11,6 +11,8 @@ from kde import gaussian_kde import mstats -__all__ = filter(lambda s:not s.startswith('_'),dir()) +#remove vonmises_cython from __all__, I don't know why it is included +__all__ = filter(lambda s:not (s.startswith('_') or s.endswith('cython')),dir()) + from numpy.testing import Tester test = Tester().test From scipy-svn at scipy.org Thu Dec 4 18:17:29 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 4 Dec 2008 17:17:29 -0600 (CST) Subject: [Scipy-svn] r5226 - trunk/scipy/stats Message-ID: <20081204231729.29E0EC7C00B@scipy.org> Author: josef Date: 2008-12-04 17:17:27 -0600 (Thu, 04 Dec 2008) New Revision: 5226 Modified: trunk/scipy/stats/distributions.py Log: correct skew, kurtosis calculation in generic stats method (cont. distr.) , this raised exception in a few cases. Some incorrect numbers for skew and kurtosis of individual distributions are left. Modified: trunk/scipy/stats/distributions.py =================================================================== --- trunk/scipy/stats/distributions.py 2008-12-04 23:11:25 UTC (rev 5225) +++ trunk/scipy/stats/distributions.py 2008-12-04 23:17:27 UTC (rev 5226) @@ -696,7 +696,8 @@ signature = inspect.getargspec(self._stats.im_func) if (signature[2] is not None) or ('moments' in signature[0]): - mu, mu2, g1, g2 = self._stats(*args,**{'moments':moments}) + #this did not fetch mv, adjust to also get mv + mu, mu2, g1, g2 = self._stats(*args,**{'moments':moments+'mv'}) else: mu, mu2, g1, g2 = self._stats(*args) if g1 is None: From scipy-svn at scipy.org Fri Dec 5 06:40:25 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Fri, 5 Dec 2008 05:40:25 -0600 (CST) Subject: [Scipy-svn] r5227 - trunk/tools/win32/build_scripts Message-ID: <20081205114025.84649C7C00B@scipy.org> Author: cdavid Date: 2008-12-05 05:40:20 -0600 (Fri, 05 Dec 2008) New Revision: 5227 Modified: trunk/tools/win32/build_scripts/pavement.py Log: Display the build log when build fails. Modified: trunk/tools/win32/build_scripts/pavement.py =================================================================== --- trunk/tools/win32/build_scripts/pavement.py 2008-12-04 23:17:27 UTC (rev 5226) +++ trunk/tools/win32/build_scripts/pavement.py 2008-12-05 11:40:20 UTC (rev 5227) @@ -274,8 +274,30 @@ def raw_build_sdist(cwd): cmd = ["python", "setup.py", "sdist", "--format=zip"] - st = subprocess.call(cmd, cwd=cwd) + build_log = "sdist.log" + f = open(build_log, 'w') + try: + try: + st = subprocess.call(cmd, #shell = True, + stderr = subprocess.STDOUT, stdout = f, + cwd=cwd) + if st: + raise RuntimeError("The cmd failed with status %d" % st) + finally: + f.close() + except (subprocess.CalledProcessError, RuntimeError), e: + print e + msg = """ +There was an error while executing the following command: + + %s + +Error was : %s + +Look at the log (%s).""" % (cmd, str(e), build_log) + raise Exception(msg) + def raw_bootstrap(pyver, src_dir): bdir = bootstrap_dir(pyver) prepare_scipy_sources(src_dir, bdir) From scipy-svn at scipy.org Fri Dec 5 21:14:54 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Fri, 5 Dec 2008 20:14:54 -0600 (CST) Subject: [Scipy-svn] r5228 - in trunk/scipy/io/matlab: . tests Message-ID: <20081206021454.EF781C7C00B@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-05 20:14:52 -0600 (Fri, 05 Dec 2008) New Revision: 5228 Modified: trunk/scipy/io/matlab/mio.py trunk/scipy/io/matlab/mio5.py trunk/scipy/io/matlab/tests/test_mio.py Log: Added neater field name length check, with test, thanks to Vebjorn Ljosa and Lee Kamentsky Modified: trunk/scipy/io/matlab/mio.py =================================================================== --- trunk/scipy/io/matlab/mio.py 2008-12-05 11:40:20 UTC (rev 5227) +++ trunk/scipy/io/matlab/mio.py 2008-12-06 02:14:52 UTC (rev 5228) @@ -150,7 +150,7 @@ elif format == '5': MW = MatFile5Writer(file_stream, unicode_strings=True) else: - raise ValueError, 'Format should be 4 or 5' + raise ValueError("Format should be '4' or '5'") MW.put_variables(mdict) if file_is_string: file_stream.close() Modified: trunk/scipy/io/matlab/mio5.py =================================================================== --- trunk/scipy/io/matlab/mio5.py 2008-12-05 11:40:20 UTC (rev 5227) +++ trunk/scipy/io/matlab/mio5.py 2008-12-06 02:14:52 UTC (rev 5228) @@ -1,4 +1,10 @@ ''' Classes for read / write of matlab (TM) 5 files + +The matfile specification last found here: + +http://www.mathworks.com/access/helpdesk/help/pdf_doc/matlab/matfile_format.pdf + +(as of December 5 2008) ''' # Small fragments of current code adapted from matfile.py by Heiko @@ -170,7 +176,7 @@ We will deprecate this method of holding struct information in a future version of scipy, in favor of the recarray method (see - loadmat doctstring) + loadmat docstring) ''' pass @@ -808,9 +814,14 @@ def write_fields(self): # write fieldnames fieldnames = [f[0] for f in self.arr.dtype.descr] - self.write_element(np.array([32], dtype='i4')) - self.write_element(np.array(fieldnames, dtype='S32'), - mdtype=miINT8) + length = max([len(fieldname) for fieldname in fieldnames])+1 + if length > 32: + raise ValueError( + "Field names are restricted to 64 characters in Matlab") + self.write_element(np.array([length], dtype='i4')) + self.write_element( + np.array(fieldnames, dtype='S%d'%(length)), + mdtype=miINT8) A = np.atleast_2d(self.arr).flatten('F') MWG = Mat5WriterGetter(self.file_stream, self.unicode_strings) Modified: trunk/scipy/io/matlab/tests/test_mio.py =================================================================== --- trunk/scipy/io/matlab/tests/test_mio.py 2008-12-05 11:40:20 UTC (rev 5227) +++ trunk/scipy/io/matlab/tests/test_mio.py 2008-12-06 02:14:52 UTC (rev 5228) @@ -337,3 +337,16 @@ def test_regression_653(): """Regression test for #653.""" assert_raises(TypeError, savemat, StringIO(), {'d':{1:2}}, format='5') + +def test_structname_len(): + # Test limit for length of field names in structs + lim = 31 + fldname = 'a' * lim + st1 = np.zeros((1,1), dtype=[(fldname, object)]) + mat_stream = StringIO() + savemat(StringIO(), {'longstruct': st1}, format='5') + fldname = 'a' * (lim+1) + st1 = np.zeros((1,1), dtype=[(fldname, object)]) + assert_raises(ValueError, savemat, StringIO(), + {'longstruct': st1}, format='5') + From scipy-svn at scipy.org Sat Dec 6 16:25:01 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 6 Dec 2008 15:25:01 -0600 (CST) Subject: [Scipy-svn] r5229 - trunk/scipy/stats Message-ID: <20081206212501.9DA7BC7C00E@scipy.org> Author: josef Date: 2008-12-06 15:24:57 -0600 (Sat, 06 Dec 2008) New Revision: 5229 Modified: trunk/scipy/stats/stats.py Log: correct cut and paste errors in docstrings, now passes doctest Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-06 02:14:52 UTC (rev 5228) +++ trunk/scipy/stats/stats.py 2008-12-06 21:24:57 UTC (rev 5229) @@ -1900,8 +1900,8 @@ This is a two-sided test for the null hypothesis that 2 independent samples have identical average (expected) values. - Description: - ------------ + Description + ----------- We can use this test, if we observe two independent samples from the same or different population, e.g. exam scores of boys and @@ -1916,23 +1916,27 @@ see: http://en.wikipedia.org/wiki/T-test#Independent_two-sample_t-test - Examples: - --------- + Examples + -------- - (note: after changes difference in 13th decimal) + >>> from scipy import stats + >>> import numpy as np - >>> np.random.seed(12345678) #fix seed to get the same result + #fix seed to get the same result + >>> np.random.seed(12345678) - test with sample with identical means + # test with sample with identical means >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) >>> stats.ttest_ind(rvs1,rvs2) - (array(0.26833823296239279), 0.78849443369561645) + (array(0.26833823296239279), 0.78849443369564765) - test with sample with different means + + # test with sample with different means >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) >>> stats.ttest_ind(rvs1,rvs3) - (array(-5.0434013458585092), 5.4302979475463849e-007) + (array(-5.0434013458585092), 5.4302979468623391e-007) + """ a, b, axis = _chk2_asarray(a, b, axis) x1 = mean(a,axis) @@ -1963,8 +1967,8 @@ Returns: t-value, two-tailed p-value - Description: - ============ + Description + ----------- This is a two-sided test for the null hypothesis that 2 repeated samples have identical average values. @@ -1981,21 +1985,25 @@ see: http://en.wikipedia.org/wiki/T-test#Dependent_t-test - Examples: - ========= + Examples + -------- (note: after changes difference in 13th decimal) - >>> np.random.seed(12345678) #fix seed to get the same result + >>> from scipy import stats + >>> import numpy as np + + #fix random seed to get the same result + >>> np.random.seed(12345678) >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) + \ stats.norm.rvs(scale=0.2,size=500) >>> stats.ttest_rel(rvs1,rvs2) - (array(0.24101764965300965), 0.80964043445809664) + (array(0.24101764965300965), 0.80964043445811562) >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) + \ stats.norm.rvs(scale=0.2,size=500) >>> stats.ttest_rel(rvs1,rvs3) - (array(-3.9995108708727929), 7.308240219165646e-005) + (array(-3.9995108708727929), 7.3082402191726459e-005) """ a, b, axis = _chk2_asarray(a, b, axis) @@ -2075,10 +2083,13 @@ >>> from scipy import stats >>> import numpy as np + >>> from scipy.stats import kstest + >>> x = np.linspace(-15,15,9) >>> kstest(x,'norm') (0.44435602715924361, 0.038850142705171065) + # fix random seed to get the same result >>> np.random.seed(987654321) >>> kstest('norm','',N=100) (0.058352892479417884, 0.88531190944151261) @@ -2105,12 +2116,24 @@ testing t distributed random variables against normal distribution ------------------------------------------------------------------ + + With 100 degrees of freedom the t distribution looks close to the normal + distribution, and the kstest does not reject the hypothesis that the sample + came from the normal distribution + >>> np.random.seed(987654321) >>> stats.kstest(stats.t.rvs(100,size=100),'norm') - (0.062018929165471248, 0.44505373063343567) + (0.072018929165471257, 0.67630062862479168) + + + With 3 degrees of freedom the t distribution looks sufficiently different + from the normal distribution, that we can reject the hypothesis that the + sample came from the normal distribution at a alpha=10% level + >>> np.random.seed(987654321) >>> stats.kstest(stats.t.rvs(3,size=100),'norm') - (0.12101689575982888, 0.049143106661937996) + (0.131016895759829, 0.058826222555312224) + """ if isinstance(rvs, basestring): #cdf = getattr(stats, rvs).cdf @@ -2195,6 +2218,11 @@ Examples: --------- + >>> from scipy import stats + >>> import numpy as np + >>> from scipy.stats import ks_2samp + + # fix random seed to get the same result >>> np.random.seed(12345678); >>> n1 = 200 # size of first sample @@ -2204,21 +2232,22 @@ we can reject the null hypothesis since the pvalue is below 1% >>> rvs1 = stats.norm.rvs(size=n1,loc=0.,scale=1); >>> rvs2 = stats.norm.rvs(size=n2,loc=0.5,scale=1.5) - >>> ks_2samp_new(rvs1,rvs2) - (0.17333333333333334, 0.0012436147919875644) + >>> ks_2samp(rvs1,rvs2) + (0.20833333333333337, 4.6674975515806989e-005) slightly different distribution - we cannot reject the null hypothesis since the pvalue is high, 43.8% + we cannot reject the null hypothesis at a 10% or lower alpha since + the pvalue at 0.144 is higher than 10% >>> rvs3 = stats.norm.rvs(size=n2,loc=0.01,scale=1.0) - >>> ks_2samp_new(rvs1,rvs3) - (0.078333333333333255, 0.4379740175003739) + >>> ks_2samp(rvs1,rvs3) + (0.10333333333333333, 0.14498781825751686) identical distribution - we cannot reject the null hypothesis since the pvalue is high, 65% + we cannot reject the null hypothesis since the pvalue is high, 41% >>> rvs4 = stats.norm.rvs(size=n2,loc=0.0,scale=1.0) - >>> ks_2samp_new(rvs1,rvs4) - (0.066666666666666652, 0.64576306820960394) - + >>> ks_2samp(rvs1,rvs4) + (0.07999999999999996, 0.41126949729859719) + """ data1, data2 = map(asarray, (data1, data2)) n1 = data1.shape[0] From scipy-svn at scipy.org Sun Dec 7 07:02:44 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 7 Dec 2008 06:02:44 -0600 (CST) Subject: [Scipy-svn] r5230 - trunk/doc/release Message-ID: <20081207120244.EB8A8C7C020@scipy.org> Author: jarrod.millman Date: 2008-12-07 06:02:43 -0600 (Sun, 07 Dec 2008) New Revision: 5230 Modified: trunk/doc/release/0.7.0-notes.rst Log: short description the matlab io changes (from Ray Jones) Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-06 21:24:57 UTC (rev 5229) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-07 12:02:43 UTC (rev 5230) @@ -63,6 +63,11 @@ * the Matlab (TM) file readers/writers have a number of improvements: * default version 5 + * v5 writers for structures, cell arrays, and objects + * v5 readers/writers for function handles and 64-bit integers + * new struct_as_record keyword argument to ``loadmat``, which loads + struct arrays in matlab as record arrays in numpy + * string arrays have ``dtype='U...'`` instead of ``dtype=object`` New Hierarchical Clustering module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From scipy-svn at scipy.org Sun Dec 7 12:31:04 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 7 Dec 2008 11:31:04 -0600 (CST) Subject: [Scipy-svn] r5231 - in trunk/scipy: ndimage optimize Message-ID: <20081207173104.21B19C7C024@scipy.org> Author: ptvirtan Date: 2008-12-07 11:30:50 -0600 (Sun, 07 Dec 2008) New Revision: 5231 Modified: trunk/scipy/ndimage/interpolation.py trunk/scipy/optimize/zeros.py Log: Docstring updates from wiki Modified: trunk/scipy/ndimage/interpolation.py =================================================================== --- trunk/scipy/ndimage/interpolation.py 2008-12-07 12:02:43 UTC (rev 5230) +++ trunk/scipy/ndimage/interpolation.py 2008-12-07 17:30:50 UTC (rev 5231) @@ -143,7 +143,8 @@ def map_coordinates(input, coordinates, output_type = None, output = None, order = 3, mode = 'constant', cval = 0.0, prefilter = True): - """Apply an arbritrary coordinate transformation. + """ + Map the input array to new coordinates by interpolation. The array of coordinates is used to find, for each point in the output, the corresponding coordinates in the input. The value of the input at @@ -153,32 +154,71 @@ The shape of the output is derived from that of the coordinate array by dropping the first axis. The values of the array along the first axis are the coordinates in the input array at which the - output value is found. For example, if the input has dimensions - (100,200,3), then the shape of coordinates will be (3,100,200,3), - where coordinates[:,1,2,3] specify the input coordinate at which - output[1,2,3] is found. + output value is found. - Points outside the boundaries of the input are filled according to - the given mode ('constant', 'nearest', 'reflect' or 'wrap'). The - parameter prefilter determines if the input is pre-filtered before - interpolation (necessary for spline interpolation of order > - 1). If False it is assumed that the input is already filtered. + Parameters + ---------- + input : ndarray + The input array + coordinates : array_like + The coordinates at which `input` is evaluated. + output_type : deprecated + Use `output` instead. + output : dtype, optional + If the output has to have a certain type, specify the dtype. + The default behavior is for the output to have the same type + as `input`. + order : int, optional + The order of the spline interpolation, default is 3. + The order has to be in the range 0-5. + mode : str, optional + Points outside the boundaries of the input are filled according + to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). + Default is 'constant'. + cval : scalar, optional + Value used for points outside the boundaries of the input if + `mode='constant`. Default is 0.0 + prefilter : bool, optional + The parameter prefilter determines if the input is + pre-filtered with `spline_filter`_ before interpolation + (necessary for spline interpolation of order > 1). + If False, it is assumed that the input is already filtered. - Example + Returns ------- - >>> a = arange(12.).reshape((4,3)) + return_value : ndarray + The result of transforming the input. The shape of the + output is derived from that of `coordinates` by dropping + the first axis. + + + See Also + -------- + spline_filter, geometric_transform, scipy.interpolate + + Examples + -------- + >>> import scipy.ndimage + >>> a = np.arange(12.).reshape((4,3)) >>> print a - [[ 0. 1. 2.] - [ 3. 4. 5.] - [ 6. 7. 8.] - [ 9. 10. 11.]] - >>> output = map_coordinates(a,[[0.5, 2], [0.5, 1]],order=1) - >>> print output - [ 2. 7.] + array([[ 0., 1., 2.], + [ 3., 4., 5.], + [ 6., 7., 8.], + [ 9., 10., 11.]]) + >>> sp.ndimage.map_coordinates(a, [[0.5, 2], [0.5, 1]], order=1) + [ 2. 7.] - Here, the interpolated value of a[0.5,0.5] gives output[0], while - a[2,1] is output[1]. + Above, the interpolated value of a[0.5, 0.5] gives output[0], while + a[2, 1] is output[1]. + >>> inds = np.array([[0.5, 2], [0.5, 4]]) + >>> sp.ndimage.map_coordinates(a, inds, order=1, cval=-33.3) + array([ 2. , -33.3]) + >>> sp.ndimage.map_coordinates(a, inds, order=1, mode='nearest') + array([ 2., 8.]) + >>> sp.ndimage.map_coordinates(a, inds, order=1, cval=0, output=bool) + array([ True, False], dtype=bool + """ if order < 0 or order > 5: raise RuntimeError, 'spline order not supported' Modified: trunk/scipy/optimize/zeros.py =================================================================== --- trunk/scipy/optimize/zeros.py 2008-12-07 12:02:43 UTC (rev 5230) +++ trunk/scipy/optimize/zeros.py 2008-12-07 17:30:50 UTC (rev 5231) @@ -99,60 +99,69 @@ def ridder(f, a, b, args=(), xtol=_xtol, rtol=_rtol, maxiter=_iter, full_output=False, disp=False): - """Find root of f in [a,b] + """ + Find a root of a function in an interval. - Ridder routine to find a zero of the function - f between the arguments a and b. f(a) and f(b) can not - have the same signs. Faster than bisection, but not - generaly as fast as the brent rountines. A description - may be found in a recent edition of Numerical Recipes. - The routine here is modified a bit to be more careful - of tolerance. - - f : Python function returning a number. - - a : Number, one end of the bracketing interval. - - b : Number, the other end of the bracketing interval. - - xtol : Number, the routine converges when a root is known + Parameters + ---------- + f : function + Python function returning a number. + `f` must be continuous, and `f(a)` and `f(b)` must have opposite signs. + a : number + one end of the bracketing interval `[a,b]` + b : number + the other end of the bracketing interval `[a,b]` + xtol : number, optional + the routine converges when a root is known to lie within xtol of the value return. Should be >= 0. The routine modifies this to take into account the relative precision of doubles. + maxiter : number, optional + if convergence is not achieved in + maxiter iterations, and error is raised. + Must be >= 0. + args : tuple, optional + containing extra arguments for the function `f`. + `f` is called by ``apply(f, (x)+args)``. + full_output : bool, optional + If `full_output` is False, the root is returned. + If `full_output` is True, the return value is ``(x, r)``, where `x` + is the root, and `r` is a RootResults object. + disp : bool, optional + If True, print a message to ``stderr`` if the algorithm didn't + converge. - maxiter : Number, if convergence is not achieved in - maxiter iterations, and error is raised. Must be - >= 0. + Returns + ------- + x0 : float + Zero of `f` between `a` and `b`. + r : RootResults (present if ``full_output = True``) + Object containing information about the convergence. + In particular, ``r.converged`` is True if the routine converged. - args : tuple containing extra arguments for the function f. - f is called by apply(f,(x)+args). + See Also + -------- + brentq, brenth, bisect, newton : one-dimensional root-finding + fixed_point : scalar fixed-point finder - If full_output is False, the root is returned. + Notes + ----- + Uses [Ridders1979]_ method to find a zero of the function `f` between + the arguments `a` and `b`. Ridders' method is faster than bisection, + but not generaly as fast as the brent rountines. [Ridders1979]_ provides + the classic description and source of the algorithm. A description can + also be found in may be found in any recent edition of Numerical Recipes. - If full_output is True, the return value is (x, r), where x - is the root, and r is a RootResults object containing information - about the convergence. In particular, r.converged is True if the - the routine converged. + The routine used here diverges slightly from standard presentations + in order to be a bit more careful of tolerance. - See also: + References + ---------- + .. [Ridders1979] + Ridders, C. F. J. "A New Algorithm for Computing a + Single Root of a Real Continuous Function." + IEEE Trans. Circuits Systems 26, 979-980, 1979. - fmin, fmin_powell, fmin_cg, - fmin_bfgs, fmin_ncg -- multivariate local optimizers - leastsq -- nonlinear least squares minimizer - - fmin_l_bfgs_b, fmin_tnc, - fmin_cobyla -- constrained multivariate optimizers - - anneal, brute -- global optimizers - - fminbound, brent, golden, bracket -- local scalar minimizers - - fsolve -- n-dimenstional root-finding - - brentq, brenth, ridder, bisect, newton -- one-dimensional root-finding - - fixed_point -- scalar fixed-point finder - """ if type(args) != type(()) : args = (args,) @@ -162,61 +171,107 @@ def brentq(f, a, b, args=(), xtol=_xtol, rtol=_rtol, maxiter=_iter, full_output=False, disp=False): - """Find root of f in [a,b] + """ + Find a root of a function in given interval. - The classic Brent routine to find a zero of the function - f between the arguments a and b. f(a) and f(b) can not - have the same signs. Generally the best of the routines here. + Return float, a zero of `f` between `a` and `b`. + `f` must be a continuous function, and + [a,b] must be a sign changing interval. + + Description: + Uses the classic Brent (1973) method to find a zero + of the function `f` on the sign changing interval [a , b]. + Generally considered the best of the rootfinding routines here. It is a safe version of the secant method that uses inverse - quadratic extrapolation. The version here is a slight - modification that uses a different formula in the extrapolation - step. A description may be found in Numerical Recipes, but the - code here is probably easier to understand. + quadratic extrapolation. + Brent's method combines root bracketing, interval bisection, + and inverse quadratic interpolation. + It is sometimes known as the van Wijngaarden-Deker-Brent method. + Brent (1973) claims convergence is guaranteed for functions + computable within [a,b]. - f : Python function returning a number. + [Brent1973]_ provides the classic description of the algorithm. + Another description is in any recent edition of Numerical Recipes, + including [PressEtal1992]_. + Another description is at http://mathworld.wolfram.com/BrentsMethod.html. + It should be easy to understand the algorithm just by reading our code. + Our code diverges a bit from standard presentations: + we choose a different formula for the extrapolation step. - a : Number, one end of the bracketing interval. - b : Number, the other end of the bracketing interval. + Parameters + ---------- - xtol : Number, the routine converges when a root is known - to lie within xtol of the value return. Should be >= 0. - The routine modifies this to take into account the relative - precision of doubles. + `f` : function + Python function returning a number. - maxiter : Number, if convergence is not achieved in - maxiter iterations, and error is raised. Must be - >= 0. + `a` : number + one end of the bracketing interval [a,b] - args : tuple containing extra arguments for the function f. - f is called by apply(f,(x)+args). + `b` : number + the other end of the bracketing interval [a,b] - If full_output is False, the root is returned. + `xtol` : number + the routine converges when a root is known + to lie within xtol of the value return. Should be >= 0. + The routine modifies this to take into account the relative + precision of doubles. - If full_output is True, the return value is (x, r), where x - is the root, and r is a RootResults object containing information - about the convergence. In particular, r.converged is True if the - the routine converged. + `maxiter` : number + if convergence is not achieved in + maxiter iterations, and error is raised. + Must be >= 0. - See also: + `args` : tuple + containing extra arguments for the function `f`. + `f` is called by apply(f,(x)+args). - fmin, fmin_powell, fmin_cg, - fmin_bfgs, fmin_ncg -- multivariate local optimizers - leastsq -- nonlinear least squares minimizer + `full_output` : bool + If `full_output` is False, the root is returned. + If `full_output` is True, the return value is (x, r), where x + is the root, and r is a RootResults object containing information + about the convergence. In particular, r.converged is True if the + the routine converged. - fmin_l_bfgs_b, fmin_tnc, - fmin_cobyla -- constrained multivariate optimizers - anneal, brute -- global optimizers + See Also + -------- - fminbound, brent, golden, bracket -- local scalar minimizers + multivariate local optimizers + `fmin`, `fmin_powell`, `fmin_cg`, `fmin_bfgs`, `fmin_ncg` + nonlinear least squares minimizer + `leastsq` + constrained multivariate optimizers + `fmin_l_bfgs_b`, `fmin_tnc`, `fmin_cobyla` + global optimizers + `anneal`, `brute` + local scalar minimizers + `fminbound`, `brent`, `golden`, `bracket` + n-dimenstional root-finding + `fsolve` + one-dimensional root-finding + `brentq`, `brenth`, `ridder`, `bisect`, `newton` + scalar fixed-point finder + `fixed_point` - fsolve -- n-dimenstional root-finding + Notes + ----- - brentq, brenth, ridder, bisect, newton -- one-dimensional root-finding + `f` must be continuous. + f(a) and f(b) must have opposite signs. - fixed_point -- scalar fixed-point finder + .. [Brent1973] + Brent, R. P., + *Algorithms for Minimization Without Derivatives*. + Englewood Cliffs, NJ: Prentice-Hall, 1973. Ch. 3-4. + + .. [PressEtal1992] + Press, W. H.; Flannery, B. P.; Teukolsky, S. A.; and Vetterling, W. T. + *Numerical Recipes in FORTRAN: The Art of Scientific Computing*, 2nd ed. + Cambridge, England: Cambridge University Press, pp. 352-355, 1992. + Section 9.3: "Van Wijngaarden-Dekker-Brent Method." + """ if type(args) != type(()) : args = (args,) From scipy-svn at scipy.org Sun Dec 7 12:45:14 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 7 Dec 2008 11:45:14 -0600 (CST) Subject: [Scipy-svn] r5232 - in trunk/scipy/interpolate: . fitpack src tests Message-ID: <20081207174514.E57F8C7C024@scipy.org> Author: ptvirtan Date: 2008-12-07 11:44:59 -0600 (Sun, 07 Dec 2008) New Revision: 5232 Added: trunk/scipy/interpolate/fitpack/bispeu.f Modified: trunk/scipy/interpolate/fitpack2.py trunk/scipy/interpolate/src/fitpack.pyf trunk/scipy/interpolate/tests/test_fitpack.py Log: interpolate: evaluating bivariate splines at arbitrary points Added: trunk/scipy/interpolate/fitpack/bispeu.f =================================================================== --- trunk/scipy/interpolate/fitpack/bispeu.f 2008-12-07 17:30:50 UTC (rev 5231) +++ trunk/scipy/interpolate/fitpack/bispeu.f 2008-12-07 17:44:59 UTC (rev 5232) @@ -0,0 +1,64 @@ + subroutine bispeu(tx,nx,ty,ny,c,kx,ky,x,y,z,m,wrk,lwrk, ier) +c subroutine bispeu evaluates on a set of points (x(i),y(i)),i=1,...,m +c a bivariate spline s(x,y) of degrees kx and ky, given in the +c b-spline representation. +c +c calling sequence: +c call bispeu(tx,nx,ty,ny,c,kx,ky,x,y,z,m,wrk,lwrk, +c * iwrk,kwrk,ier) +c +c input parameters: +c tx : real array, length nx, which contains the position of the +c knots in the x-direction. +c nx : integer, giving the total number of knots in the x-direction +c ty : real array, length ny, which contains the position of the +c knots in the y-direction. +c ny : integer, giving the total number of knots in the y-direction +c c : real array, length (nx-kx-1)*(ny-ky-1), which contains the +c b-spline coefficients. +c kx,ky : integer values, giving the degrees of the spline. +c x : real array of dimension (mx). +c y : real array of dimension (my). +c m : on entry m must specify the number points. m >= 1. +c wrk : real array of dimension lwrk. used as workspace. +c lwrk : integer, specifying the dimension of wrk. +c lwrk >= kx+ky+2 +c +c output parameters: +c z : real array of dimension m. +c on succesful exit z(i) contains the value of s(x,y) +c at the point (x(i),y(i)), i=1,...,m. +c ier : integer error flag +c ier=0 : normal return +c ier=10: invalid input data (see restrictions) +c +c restrictions: +c m >=1, lwrk>=mx*(kx+1)+my*(ky+1), kwrk>=mx+my +c tx(kx+1) <= x(i-1) <= x(i) <= tx(nx-kx), i=2,...,mx +c ty(ky+1) <= y(j-1) <= y(j) <= ty(ny-ky), j=2,...,my +c +c other subroutines required: +c fpbisp,fpbspl +c +c ..scalar arguments.. + integer nx,ny,kx,ky,m,lwrk,kwrk,ier +c ..array arguments.. + real*8 tx(nx),ty(ny),c((nx-kx-1)*(ny-ky-1)),x(m),y(m),z(m), + * wrk(lwrk) +c ..local scalars.. + integer iwrk(2) + integer i,iw,lwest +c .. +c before starting computations a data check is made. if the input data +c are invalid control is immediately repassed to the calling program. + ier = 10 + lwest = kx+ky+2 + if (lwrk.lt.lwest) go to 100 + if (m.lt.1) go to 100 + ier = 0 + do 10 i=1,m + call fpbisp(tx,nx,ty,ny,c,kx,ky,x(i),1,y(i),1,z(i),wrk(1), + * wrk(kx+2),iwrk(1),iwrk(2)) + 10 continue + 100 return + end Modified: trunk/scipy/interpolate/fitpack2.py =================================================================== --- trunk/scipy/interpolate/fitpack2.py 2008-12-07 17:30:50 UTC (rev 5231) +++ trunk/scipy/interpolate/fitpack2.py 2008-12-07 17:44:59 UTC (rev 5232) @@ -362,6 +362,16 @@ return z raise NotImplementedError + def ev(self, xi, yi): + """ + Evaluate spline at points (x[i], y[i]), i=0,...,len(x)-1 + """ + tx,ty,c = self.tck[:3] + kx,ky = self.degrees + zi,ier = dfitpack.bispeu(tx,ty,c,kx,ky,xi,yi) + assert ier==0, 'Invalid input: ier='+`ier` + return zi + def integral(self, xa, xb, ya, yb): """ Evaluate the integral of the spline over area [xa,xb] x [ya,yb]. Modified: trunk/scipy/interpolate/src/fitpack.pyf =================================================================== --- trunk/scipy/interpolate/src/fitpack.pyf 2008-12-07 17:30:50 UTC (rev 5231) +++ trunk/scipy/interpolate/src/fitpack.pyf 2008-12-07 17:44:59 UTC (rev 5232) @@ -329,6 +329,25 @@ integer intent(out) :: ier end subroutine bispev + subroutine bispeu(tx,nx,ty,ny,c,kx,ky,x,y,z,m,wrk,lwrk,ier) + ! z,ier = bispeu(tx,ty,c,kx,ky,x,y) + real*8 dimension(nx),intent(in) :: tx + integer intent(hide),depend(tx) :: nx=len(tx) + real*8 dimension(ny),intent(in) :: ty + integer intent(hide),depend(ty) :: ny=len(ty) + real*8 intent(in),dimension((nx-kx-1)*(ny-ky-1)),depend(nx,ny,kx,ky),& + check(len(c)==(nx-kx-1)*(ny-ky-1)):: c + integer :: kx + integer :: ky + real*8 intent(in),dimension(m) :: x + real*8 intent(in),dimension(m) :: y + integer intent(hide),depend(x) :: m=len(x) + real*8 dimension(m),depend(m),intent(out,c) :: z + real*8 dimension(lwrk),depend(lwrk),intent(hide,cache) :: wrk + integer intent(hide),depend(kx,ky) :: lwrk=kx+ky+2 + integer intent(out) :: ier + end subroutine bispeu + subroutine surfit_smth(iopt,m,x,y,z,w,xb,xe,yb,ye,kx,ky,s,nxest,nyest,& nmax,eps,nx,tx,ny,ty,c,fp,wrk1,lwrk1,wrk2,lwrk2,& iwrk,kwrk,ier) Modified: trunk/scipy/interpolate/tests/test_fitpack.py =================================================================== --- trunk/scipy/interpolate/tests/test_fitpack.py 2008-12-07 17:30:50 UTC (rev 5231) +++ trunk/scipy/interpolate/tests/test_fitpack.py 2008-12-07 17:44:59 UTC (rev 5232) @@ -150,5 +150,18 @@ lut = RectBivariateSpline(x,y,z) assert_array_almost_equal(lut(x,y),z) + def test_evaluate(self): + x = array([1,2,3,4,5]) + y = array([1,2,3,4,5]) + z = array([[1,2,1,2,1],[1,2,1,2,1],[1,2,3,2,1],[1,2,2,2,1],[1,2,1,2,1]]) + lut = RectBivariateSpline(x,y,z) + + xi = [1, 2.3, 5.3, 0.5, 3.3, 1.2, 3] + yi = [1, 3.3, 1.2, 4.0, 5.0, 1.0, 3] + zi = lut.ev(xi, yi) + zi2 = array([lut(xp, yp)[0,0] for xp, yp in zip(xi, yi)]) + + assert_almost_equal(zi, zi2) + if __name__ == "__main__": run_module_suite() From scipy-svn at scipy.org Sun Dec 7 17:05:38 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 7 Dec 2008 16:05:38 -0600 (CST) Subject: [Scipy-svn] r5233 - in trunk/doc: . source Message-ID: <20081207220538.B56C1C7C00E@scipy.org> Author: ptvirtan Date: 2008-12-07 16:05:26 -0600 (Sun, 07 Dec 2008) New Revision: 5233 Modified: trunk/doc/Makefile trunk/doc/source/conf.py Log: docs: more support for htmlhelp Modified: trunk/doc/Makefile =================================================================== --- trunk/doc/Makefile 2008-12-07 17:44:59 UTC (rev 5232) +++ trunk/doc/Makefile 2008-12-07 22:05:26 UTC (rev 5233) @@ -36,13 +36,14 @@ dist: html test -d build/latex || make latex -make -C build/latex all-pdf + -test -d build/htmlhelp || make htmlhelp-build -rm -rf build/dist - mkdir -p build/dist - cp -r build/html build/dist/reference + cp -r build/html build/dist touch build/dist/index.html - perl -pi -e 's#^\s*(
  • SciPy.*?Reference Guide.*?»
  • )\s*$$#
  • Numpy and Scipy Documentation »
  • $$1#;' build/dist/*.html build/dist/*/*.html build/dist/*/*/*.html + perl -pi -e 's#^\s*(
  • SciPy.*?Manual.*?»
  • )\s*$$#
  • Numpy and Scipy Documentation »
  • $$1#;' build/dist/*.html build/dist/*/*.html build/dist/*/*/*.html (cd build/html && zip -9qr ../dist/scipy-html.zip .) - cp build/latex/*.pdf build/dist + cp build/latex/scipy.pdf build/dist + -cp build/htmlhelp/scipy.chm build/dist cd build/dist && tar czf ../dist.tar.gz * chmod ug=rwX,o=rX -R build/dist find build/dist -type d -print0 | xargs -0r chmod g+s @@ -78,10 +79,15 @@ @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in build/htmlhelp." +htmlhelp-build: htmlhelp build/htmlhelp/scipy.chm +%.chm: %.hhp + -hhc.exe $^ + latex: generate mkdir -p build/latex build/doctrees $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex python postprocess.py tex build/latex/*.tex + perl -pi -e 's/\t(latex.*|pdflatex) (.*)/\t-$$1 -interaction batchmode $$2/' build/latex/Makefile @echo @echo "Build finished; the LaTeX files are in build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ @@ -106,4 +112,4 @@ "or in build/linkcheck/output.txt." .PHONY: help clean upload dist generate html pickle web htmlhelp latex \ - coverage changes linkcheck + coverage changes linkcheck htmlhelp-build Modified: trunk/doc/source/conf.py =================================================================== --- trunk/doc/source/conf.py 2008-12-07 17:44:59 UTC (rev 5232) +++ trunk/doc/source/conf.py 2008-12-07 22:05:26 UTC (rev 5233) @@ -69,7 +69,7 @@ # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -show_authors = True +show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' @@ -86,7 +86,7 @@ # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = "%s v%s Reference Guide (DRAFT)" % (project, version) +html_title = "%s v%s Manual (DRAFT)" % (project, version) # The name of an image file (within the static path) to place at the top of # the sidebar. @@ -132,7 +132,7 @@ html_file_suffix = '.html' # Output file base name for HTML help builder. -htmlhelp_basename = 'NumPydoc' +htmlhelp_basename = 'scipy' # Pngmath should try to align formulas properly pngmath_use_preview = True @@ -152,8 +152,7 @@ # (source start file, target name, title, author, document class [howto/manual]). _stdauthor = 'Written by the SciPy community' latex_documents = [ - ('index', 'scipy-ref.tex', 'SciPy Reference Guide', - _stdauthor, 'manual'), + ('index', 'scipy.tex', 'SciPy Guide', _stdauthor, 'manual'), # ('user/index', 'scipy-user.tex', 'SciPy User Guide', # _stdauthor, 'manual'), ] From scipy-svn at scipy.org Sun Dec 7 17:06:15 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 7 Dec 2008 16:06:15 -0600 (CST) Subject: [Scipy-svn] r5234 - in trunk/doc/source: . tutorial Message-ID: <20081207220615.B98A9C7C00E@scipy.org> Author: ptvirtan Date: 2008-12-07 16:05:52 -0600 (Sun, 07 Dec 2008) New Revision: 5234 Added: trunk/doc/source/tutorial/basic.rst trunk/doc/source/tutorial/general.rst trunk/doc/source/tutorial/integrate.rst trunk/doc/source/tutorial/interpolate.rst trunk/doc/source/tutorial/linalg.rst trunk/doc/source/tutorial/optimize.rst trunk/doc/source/tutorial/signal.rst trunk/doc/source/tutorial/special.rst trunk/doc/source/tutorial/stats.rst Modified: trunk/doc/source/index.rst trunk/doc/source/tutorial/index.rst Log: docs: split the tutorial to parts Modified: trunk/doc/source/index.rst =================================================================== --- trunk/doc/source/index.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/index.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -6,9 +6,13 @@ science, and engineering. .. toctree:: + :maxdepth: 2 + + tutorial/index + +.. toctree:: :maxdepth: 1 - tutorial/index release Reference Added: trunk/doc/source/tutorial/basic.rst =================================================================== --- trunk/doc/source/tutorial/basic.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/basic.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -0,0 +1,298 @@ +Basic functions in Numpy (and top-level scipy) +============================================== + +.. sectionauthor:: Travis E. Oliphant + +.. currentmodule:: numpy + +Interaction with Numpy +------------------------ + +To begin with, all of the Numpy functions have been subsumed into the +:mod:`scipy` namespace so that all of those functions are available +without additionally importing Numpy. In addition, the universal +functions (addition, subtraction, division) have been altered to not +raise exceptions if floating-point errors are encountered; instead, +NaN's and Inf's are returned in the arrays. To assist in detection of +these events, several functions (:func:`isnan`, :func:`isfinite`, +:func:`isinf`) are available. + +Finally, some of the basic functions like log, sqrt, and inverse trig +functions have been modified to return complex numbers instead of +NaN's where appropriate (*i.e.* ``scipy.sqrt(-1)`` returns ``1j``). + + +Top-level scipy routines +------------------------ + +The purpose of the top level of scipy is to collect general-purpose +routines that the other sub-packages can use and to provide a simple +replacement for Numpy. Anytime you might think to import Numpy, you +can import scipy instead and remove yourself from direct dependence on +Numpy. These routines are divided into several files for +organizational purposes, but they are all available under the numpy +namespace (and the scipy namespace). There are routines for type +handling and type checking, shape and matrix manipulation, polynomial +processing, and other useful functions. Rather than giving a detailed +description of each of these functions (which is available in the +Numpy Reference Guide or by using the :func:`help`, :func:`info` and +:func:`source` commands), this tutorial will discuss some of the more +useful commands which require a little introduction to use to their +full potential. + + +Type handling +^^^^^^^^^^^^^ + +Note the difference between :func:`iscomplex` (:func:`isreal`) and +:func:`iscomplexobj` (:func:`isrealobj`). The former command is +array based and returns byte arrays of ones and zeros providing the +result of the element-wise test. The latter command is object based +and returns a scalar describing the result of the test on the entire +object. + +Often it is required to get just the real and/or imaginary part of a +complex number. While complex numbers and arrays have attributes that +return those values, if one is not sure whether or not the object will +be complex-valued, it is better to use the functional forms +:func:`real` and :func:`imag` . These functions succeed for anything +that can be turned into a Numpy array. Consider also the function +:func:`real_if_close` which transforms a complex-valued number with +tiny imaginary part into a real number. + +Occasionally the need to check whether or not a number is a scalar +(Python (long)int, Python float, Python complex, or rank-0 array) +occurs in coding. This functionality is provided in the convenient +function :func:`isscalar` which returns a 1 or a 0. + +Finally, ensuring that objects are a certain Numpy type occurs often +enough that it has been given a convenient interface in SciPy through +the use of the :obj:`cast` dictionary. The dictionary is keyed by the +type it is desired to cast to and the dictionary stores functions to +perform the casting. Thus, ``>>> a = cast['f'](d)`` returns an array +of :class:`float32` from *d*. This function is also useful as an easy +way to get a scalar of a certain type: ``>>> fpi = cast['f'](pi)``. + + +Index Tricks +^^^^^^^^^^^^ + +Thre are some class instances that make special use of the slicing +functionality to provide efficient means for array construction. This +part will discuss the operation of :obj:`mgrid` , :obj:`ogrid` , +:obj:`r_` , and :obj:`c_` for quickly constructing arrays. + +One familiar with Matlab may complain that it is difficult to +construct arrays from the interactive session with Python. Suppose, +for example that one wants to construct an array that begins with 3 +followed by 5 zeros and then contains 10 numbers spanning the range -1 +to 1 (inclusive on both ends). Before SciPy, you would need to enter +something like the following + + >>> concatenate(([3],[0]*5,arange(-1,1.002,2/9.0))) + +With the :obj:`r_` command one can enter this as + + >>> r_[3,[0]*5,-1:1:10j] + +which can ease typing and make for more readable code. Notice how +objects are concatenated, and the slicing syntax is (ab)used to +construct ranges. The other term that deserves a little explanation is +the use of the complex number 10j as the step size in the slicing +syntax. This non-standard use allows the number to be interpreted as +the number of points to produce in the range rather than as a step +size (note we would have used the long integer notation, 10L, but this +notation may go away in Python as the integers become unified). This +non-standard usage may be unsightly to some, but it gives the user the +ability to quickly construct complicated vectors in a very readable +fashion. When the number of points is specified in this way, the end- +point is inclusive. + +The "r" stands for row concatenation because if the objects between +commas are 2 dimensional arrays, they are stacked by rows (and thus +must have commensurate columns). There is an equivalent command +:obj:`c_` that stacks 2d arrays by columns but works identically to +:obj:`r_` for 1d arrays. + +Another very useful class instance which makes use of extended slicing +notation is the function :obj:`mgrid`. In the simplest case, this +function can be used to construct 1d ranges as a convenient substitute +for arange. It also allows the use of complex-numbers in the step-size +to indicate the number of points to place between the (inclusive) +end-points. The real purpose of this function however is to produce N, +N-d arrays which provide coordinate arrays for an N-dimensional +volume. The easiest way to understand this is with an example of its +usage: + + >>> mgrid[0:5,0:5] + array([[[0, 0, 0, 0, 0], + [1, 1, 1, 1, 1], + [2, 2, 2, 2, 2], + [3, 3, 3, 3, 3], + [4, 4, 4, 4, 4]], + [[0, 1, 2, 3, 4], + [0, 1, 2, 3, 4], + [0, 1, 2, 3, 4], + [0, 1, 2, 3, 4], + [0, 1, 2, 3, 4]]]) + >>> mgrid[0:5:4j,0:5:4j] + array([[[ 0. , 0. , 0. , 0. ], + [ 1.6667, 1.6667, 1.6667, 1.6667], + [ 3.3333, 3.3333, 3.3333, 3.3333], + [ 5. , 5. , 5. , 5. ]], + [[ 0. , 1.6667, 3.3333, 5. ], + [ 0. , 1.6667, 3.3333, 5. ], + [ 0. , 1.6667, 3.3333, 5. ], + [ 0. , 1.6667, 3.3333, 5. ]]]) + +Having meshed arrays like this is sometimes very useful. However, it +is not always needed just to evaluate some N-dimensional function over +a grid due to the array-broadcasting rules of Numpy and SciPy. If this +is the only purpose for generating a meshgrid, you should instead use +the function :obj:`ogrid` which generates an "open "grid using NewAxis +judiciously to create N, N-d arrays where only one dimension in each +array has length greater than 1. This will save memory and create the +same result if the only purpose for the meshgrid is to generate sample +points for evaluation of an N-d function. + + +Shape manipulation +^^^^^^^^^^^^^^^^^^ + +In this category of functions are routines for squeezing out length- +one dimensions from N-dimensional arrays, ensuring that an array is at +least 1-, 2-, or 3-dimensional, and stacking (concatenating) arrays by +rows, columns, and "pages "(in the third dimension). Routines for +splitting arrays (roughly the opposite of stacking arrays) are also +available. + + +Polynomials +^^^^^^^^^^^ + +There are two (interchangeable) ways to deal with 1-d polynomials in +SciPy. The first is to use the :class:`poly1d` class from Numpy. This +class accepts coefficients or polynomial roots to initialize a +polynomial. The polynomial object can then be manipulated in algebraic +expressions, integrated, differentiated, and evaluated. It even prints +like a polynomial: + + >>> p = poly1d([3,4,5]) + >>> print p + 2 + 3 x + 4 x + 5 + >>> print p*p + 4 3 2 + 9 x + 24 x + 46 x + 40 x + 25 + >>> print p.integ(k=6) + 3 2 + x + 2 x + 5 x + 6 + >>> print p.deriv() + 6 x + 4 + >>> p([4,5]) + array([ 69, 100]) + +The other way to handle polynomials is as an array of coefficients +with the first element of the array giving the coefficient of the +highest power. There are explicit functions to add, subtract, +multiply, divide, integrate, differentiate, and evaluate polynomials +represented as sequences of coefficients. + + +Vectorizing functions (vectorize) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +One of the features that NumPy provides is a class :obj:`vectorize` to +convert an ordinary Python function which accepts scalars and returns +scalars into a "vectorized-function" with the same broadcasting rules +as other Numpy functions (*i.e.* the Universal functions, or +ufuncs). For example, suppose you have a Python function named +:obj:`addsubtract` defined as: + + >>> def addsubtract(a,b): + ... if a > b: + ... return a - b + ... else: + ... return a + b + +which defines a function of two scalar variables and returns a scalar +result. The class vectorize can be used to "vectorize "this function so that :: + + >>> vec_addsubtract = vectorize(addsubtract) + +returns a function which takes array arguments and returns an array +result: + + >>> vec_addsubtract([0,3,6,9],[1,3,5,7]) + array([1, 6, 1, 2]) + +This particular function could have been written in vector form +without the use of :obj:`vectorize` . But, what if the function you have written is the result of some +optimization or integration routine. Such functions can likely only be +vectorized using ``vectorize.`` + + +Other useful functions +^^^^^^^^^^^^^^^^^^^^^^ + +There are several other functions in the scipy_base package including +most of the other functions that are also in the Numpy package. The +reason for duplicating these functions is to allow SciPy to +potentially alter their original interface and make it easier for +users to know how to get access to functions + + >>> from scipy import * + +Functions which should be mentioned are :obj:`mod(x,y)` which can +replace ``x % y`` when it is desired that the result take the sign of +*y* instead of *x* . Also included is :obj:`fix` which always rounds +to the nearest integer towards zero. For doing phase processing, the +functions :func:`angle`, and :obj:`unwrap` are also useful. Also, the +:obj:`linspace` and :obj:`logspace` functions return equally spaced samples +in a linear or log scale. Finally, it's useful to be aware of the indexing +capabilities of Numpy.mention should be made of the new +function :obj:`select` which extends the functionality of :obj:`where` to +include multiple conditions and multiple choices. The calling +convention is ``select(condlist,choicelist,default=0).`` :obj:`select` is +a vectorized form of the multiple if-statement. It allows rapid +construction of a function which returns an array of results based on +a list of conditions. Each element of the return array is taken from +the array in a ``choicelist`` corresponding to the first condition in +``condlist`` that is true. For example + + >>> x = r_[-2:3] + >>> x + array([-2, -1, 0, 1, 2]) + >>> select([x > 3, x >= 0],[0,x+2]) + array([0, 0, 2, 3, 4]) + + +Common functions +---------------- + +Some functions depend on sub-packages of SciPy but should be available +from the top-level of SciPy due to their common use. These are +functions that might have been placed in scipy_base except for their +dependence on other sub-packages of SciPy. For example the +:obj:`factorial` and :obj:`comb` functions compute :math:`n!` and +:math:`n!/k!(n-k)!` using either exact integer arithmetic (thanks to +Python's Long integer object), or by using floating-point precision +and the gamma function. The functions :obj:`rand` and :obj:`randn` +are used so often that they warranted a place at the top level. There +are convenience functions for the interactive use: :obj:`disp` +(similar to print), and :obj:`who` (returns a list of defined +variables and memory consumption--upper bounded). Another function +returns a common image used in image processing: :obj:`lena`. + +Finally, two functions are provided that are useful for approximating +derivatives of functions using discrete-differences. The function +:obj:`central_diff_weights` returns weighting coefficients for an +equally-spaced :math:`N`-point approximation to the derivative of +order *o*. These weights must be multiplied by the function +corresponding to these points and the results added to obtain the +derivative approximation. This function is intended for use when only +samples of the function are avaiable. When the function is an object +that can be handed to a routine and evaluated, the function +:obj:`derivative` can be used to automatically evaluate the object at +the correct points to obtain an N-point approximation to the *o*-th +derivative at a given point. Added: trunk/doc/source/tutorial/general.rst =================================================================== --- trunk/doc/source/tutorial/general.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/general.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -0,0 +1,92 @@ +General information +=================== + +Examples in this tutorial +------------------------- + +Throughout this tutorial it is assumed that the user +has imported all of the names defined in the SciPy top-level namespace +using the command + + >>> from scipy import * + +Scipy sub-packages need to be imported separately, for example + + >>> from scipy import linalg, optimize + + +Finding Documentation +--------------------- + +Scipy and Numpy have HTML and PDF versions of their documentation +available at http://docs.scipy.org/, which currently details nearly +all available functionality. However, this documentation is still +work-in-progress, and some parts may be incomplete or sparse. + +Python also provides the facility of documentation strings. The +functions and classes available in SciPy use this method for on-line +documentation. There are two methods for reading these messages and +getting help. Python provides the command :func:`help` in the pydoc +module. Entering this command with no arguments (i.e. ``>>> help`` ) +launches an interactive help session that allows searching through the +keywords and modules available to all of Python. Running the command +help with an object as the argument displays the calling signature, +and the documentation string of the object. + +The pydoc method of help is sophisticated but uses a pager to display +the text. Sometimes this can interfere with the terminal you are +running the interactive session within. A scipy-specific help system +is also available under the command scipy.info. The signature and +documentation string for the object passed to the help command are +printed to standard output (or to a writeable object passed as the +third argument). The second keyword argument of "scipy.info" defines +the maximum width of the line for printing. If a module is passed as +the argument to help than a list of the functions and classes defined +in that module is printed. For example: + +.. literalinclude:: examples/1-1 + +Another useful command is :func:`source`. When given a function +written in Python as an argument, it prints out a listing of the +source code for that function. This can be helpful in learning about +an algorithm or understanding exactly what a function is doing with +its arguments. Also don't forget about the Python command ``dir`` +which can be used to look at the namespace of a module or package. + +SciPy Organization +------------------ + +SciPy is organized into subpackages covering different scientific +computing domains. These are summarized in the following table: + +.. currentmodule:: scipy + +================== ===================================================================== +Subpackage Description +================== ===================================================================== +:mod:`cluster` Clustering algorithms +:mod:`constants` Physical and mathematical constants +:mod:`fftpack` Fast Fourier Transform routines +:mod:`integrate` Integration and ordinary differential equation solvers +:mod:`interpolate` Interpolation and smoothing splines +:mod:`io` Input and Output +:mod:`linalg` Linear algebra +:mod:`maxentropy` Maximum entropy methods +:mod:`ndimage` N-dimensional image processing +:mod:`odr` Orthogonal distance regression +:mod:`optimize` Optimization and root-finding routines +:mod:`signal` Signal processing +:mod:`sparse` Sparse matrices and associated routines +:mod:`spatial` Spatial data structures and algorithms +:mod:`special` Special functions +:mod:`stats` Statistical distributions and functions +:mod:`weave` C/C++ integration +================== ===================================================================== + +Because of their ubiquitousness, some of the functions in these +subpackages are also made available in the scipy namespace to ease +their use in interactive sessions and programs. In addition, many +basic array functions from :mod:`numpy` are also available at the +top-level of the :mod:`scipy` package. Before looking at the +sub-packages individually, we will first look at some of these common +functions. Modified: trunk/doc/source/tutorial/index.rst =================================================================== --- trunk/doc/source/tutorial/index.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/index.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -1,15 +1,9 @@ -############## +************** SciPy Tutorial -############## +************** .. sectionauthor:: Travis E. Oliphant -.. currentmodule:: scipy - - -Introduction -============ - SciPy is a collection of mathematical algorithms and convenience functions built on the Numpy extension for Python. It adds significant power to the interactive Python session by exposing the @@ -34,2809 +28,19 @@ package. Some general Python facility is also assumed such as could be acquired by working through the Tutorial in the Python distribution. For further introductory help the user is directed to the Numpy -documentation. Throughout this tutorial it is assumed that the user -has imported all of the names defined in the SciPy top-level namespace -using the command +documentation. - >>> from scipy import * -Scipy sub-packages need to be imported separately, for example +.. toctree:: + :maxdepth: 1 - >>> from scipy import linalg, optimize + general + basic + special + integrate + optimize + interpolate + signal + linalg + stats -General Help ------------- - -Scipy and Numpy have HTML and PDF versions of their documentation -available at http://docs.scipy.org/, which currently details nearly -all available functionality. However, this documentation is still -work-in-progress, and some parts may be incomplete or sparse. - -Python also provides the facility of documentation strings. The -functions and classes available in SciPy use this method for on-line -documentation. There are two methods for reading these messages and -getting help. Python provides the command :func:`help` in the pydoc -module. Entering this command with no arguments (i.e. ``>>> help`` ) -launches an interactive help session that allows searching through the -keywords and modules available to all of Python. Running the command -help with an object as the argument displays the calling signature, -and the documentation string of the object. - -The pydoc method of help is sophisticated but uses a pager to display -the text. Sometimes this can interfere with the terminal you are -running the interactive session within. A scipy-specific help system -is also available under the command scipy.info. The signature and -documentation string for the object passed to the help command are -printed to standard output (or to a writeable object passed as the -third argument). The second keyword argument of "scipy.info" defines -the maximum width of the line for printing. If a module is passed as -the argument to help than a list of the functions and classes defined -in that module is printed. For example: - -.. literalinclude:: examples/1-1 - -Another useful command is :func:`source`. When given a function -written in Python as an argument, it prints out a listing of the -source code for that function. This can be helpful in learning about -an algorithm or understanding exactly what a function is doing with -its arguments. Also don't forget about the Python command ``dir`` -which can be used to look at the namespace of a module or package. - - -SciPy Organization ------------------- - -SciPy is organized into subpackages covering different scientific -computing domains. These are summarized in the following table: - -.. currentmodule:: scipy - -================== ===================================================================== -Subpackage Description -================== ===================================================================== -:mod:`cluster` Clustering algorithms -:mod:`constants` Physical and mathematical constants -:mod:`fftpack` Fast Fourier Transform routines -:mod:`integrate` Integration and ordinary differential equation solvers -:mod:`interpolate` Interpolation and smoothing splines -:mod:`io` Input and Output -:mod:`linalg` Linear algebra -:mod:`maxentropy` Maximum entropy methods -:mod:`ndimage` N-dimensional image processing -:mod:`odr` Orthogonal distance regression -:mod:`optimize` Optimization and root-finding routines -:mod:`signal` Signal processing -:mod:`sparse` Sparse matrices and associated routines -:mod:`spatial` Spatial data structures and algorithms -:mod:`special` Special functions -:mod:`stats` Statistical distributions and functions -:mod:`weave` C/C++ integration -================== ===================================================================== - -Because of their ubiquitousness, some of the functions in these -subpackages are also made available in the scipy namespace to ease -their use in interactive sessions and programs. In addition, many -basic array functions from :mod:`numpy` are also available at the -top-level of the :mod:`scipy` package. Before looking at the -sub-packages individually, we will first look at some of these common -functions. - - -Basic functions in Numpy (and top-level scipy) -============================================== - -.. currentmodule:: numpy - -Interaction with Numpy ------------------------- - -To begin with, all of the Numpy functions have been subsumed into the -:mod:`scipy` namespace so that all of those functions are available -without additionally importing Numpy. In addition, the universal -functions (addition, subtraction, division) have been altered to not -raise exceptions if floating-point errors are encountered; instead, -NaN's and Inf's are returned in the arrays. To assist in detection of -these events, several functions (:func:`isnan`, :func:`isfinite`, -:func:`isinf`) are available. - -Finally, some of the basic functions like log, sqrt, and inverse trig -functions have been modified to return complex numbers instead of -NaN's where appropriate (*i.e.* ``scipy.sqrt(-1)`` returns ``1j``). - - -Top-level scipy routines ------------------------- - -The purpose of the top level of scipy is to collect general-purpose -routines that the other sub-packages can use and to provide a simple -replacement for Numpy. Anytime you might think to import Numpy, you -can import scipy instead and remove yourself from direct dependence on -Numpy. These routines are divided into several files for -organizational purposes, but they are all available under the numpy -namespace (and the scipy namespace). There are routines for type -handling and type checking, shape and matrix manipulation, polynomial -processing, and other useful functions. Rather than giving a detailed -description of each of these functions (which is available in the -Numpy Reference Guide or by using the :func:`help`, :func:`info` and -:func:`source` commands), this tutorial will discuss some of the more -useful commands which require a little introduction to use to their -full potential. - - -Type handling -^^^^^^^^^^^^^ - -Note the difference between :func:`iscomplex` (:func:`isreal`) and -:func:`iscomplexobj` (:func:`isrealobj`). The former command is -array based and returns byte arrays of ones and zeros providing the -result of the element-wise test. The latter command is object based -and returns a scalar describing the result of the test on the entire -object. - -Often it is required to get just the real and/or imaginary part of a -complex number. While complex numbers and arrays have attributes that -return those values, if one is not sure whether or not the object will -be complex-valued, it is better to use the functional forms -:func:`real` and :func:`imag` . These functions succeed for anything -that can be turned into a Numpy array. Consider also the function -:func:`real_if_close` which transforms a complex-valued number with -tiny imaginary part into a real number. - -Occasionally the need to check whether or not a number is a scalar -(Python (long)int, Python float, Python complex, or rank-0 array) -occurs in coding. This functionality is provided in the convenient -function :func:`isscalar` which returns a 1 or a 0. - -Finally, ensuring that objects are a certain Numpy type occurs often -enough that it has been given a convenient interface in SciPy through -the use of the :obj:`cast` dictionary. The dictionary is keyed by the -type it is desired to cast to and the dictionary stores functions to -perform the casting. Thus, ``>>> a = cast['f'](d)`` returns an array -of :class:`float32` from *d*. This function is also useful as an easy -way to get a scalar of a certain type: ``>>> fpi = cast['f'](pi)``. - - -Index Tricks -^^^^^^^^^^^^ - -Thre are some class instances that make special use of the slicing -functionality to provide efficient means for array construction. This -part will discuss the operation of :obj:`mgrid` , :obj:`ogrid` , -:obj:`r_` , and :obj:`c_` for quickly constructing arrays. - -One familiar with Matlab may complain that it is difficult to -construct arrays from the interactive session with Python. Suppose, -for example that one wants to construct an array that begins with 3 -followed by 5 zeros and then contains 10 numbers spanning the range -1 -to 1 (inclusive on both ends). Before SciPy, you would need to enter -something like the following - - >>> concatenate(([3],[0]*5,arange(-1,1.002,2/9.0))) - -With the :obj:`r_` command one can enter this as - - >>> r_[3,[0]*5,-1:1:10j] - -which can ease typing and make for more readable code. Notice how -objects are concatenated, and the slicing syntax is (ab)used to -construct ranges. The other term that deserves a little explanation is -the use of the complex number 10j as the step size in the slicing -syntax. This non-standard use allows the number to be interpreted as -the number of points to produce in the range rather than as a step -size (note we would have used the long integer notation, 10L, but this -notation may go away in Python as the integers become unified). This -non-standard usage may be unsightly to some, but it gives the user the -ability to quickly construct complicated vectors in a very readable -fashion. When the number of points is specified in this way, the end- -point is inclusive. - -The "r" stands for row concatenation because if the objects between -commas are 2 dimensional arrays, they are stacked by rows (and thus -must have commensurate columns). There is an equivalent command -:obj:`c_` that stacks 2d arrays by columns but works identically to -:obj:`r_` for 1d arrays. - -Another very useful class instance which makes use of extended slicing -notation is the function :obj:`mgrid`. In the simplest case, this -function can be used to construct 1d ranges as a convenient substitute -for arange. It also allows the use of complex-numbers in the step-size -to indicate the number of points to place between the (inclusive) -end-points. The real purpose of this function however is to produce N, -N-d arrays which provide coordinate arrays for an N-dimensional -volume. The easiest way to understand this is with an example of its -usage: - - >>> mgrid[0:5,0:5] - array([[[0, 0, 0, 0, 0], - [1, 1, 1, 1, 1], - [2, 2, 2, 2, 2], - [3, 3, 3, 3, 3], - [4, 4, 4, 4, 4]], - [[0, 1, 2, 3, 4], - [0, 1, 2, 3, 4], - [0, 1, 2, 3, 4], - [0, 1, 2, 3, 4], - [0, 1, 2, 3, 4]]]) - >>> mgrid[0:5:4j,0:5:4j] - array([[[ 0. , 0. , 0. , 0. ], - [ 1.6667, 1.6667, 1.6667, 1.6667], - [ 3.3333, 3.3333, 3.3333, 3.3333], - [ 5. , 5. , 5. , 5. ]], - [[ 0. , 1.6667, 3.3333, 5. ], - [ 0. , 1.6667, 3.3333, 5. ], - [ 0. , 1.6667, 3.3333, 5. ], - [ 0. , 1.6667, 3.3333, 5. ]]]) - -Having meshed arrays like this is sometimes very useful. However, it -is not always needed just to evaluate some N-dimensional function over -a grid due to the array-broadcasting rules of Numpy and SciPy. If this -is the only purpose for generating a meshgrid, you should instead use -the function :obj:`ogrid` which generates an "open "grid using NewAxis -judiciously to create N, N-d arrays where only one dimension in each -array has length greater than 1. This will save memory and create the -same result if the only purpose for the meshgrid is to generate sample -points for evaluation of an N-d function. - - -Shape manipulation -^^^^^^^^^^^^^^^^^^ - -In this category of functions are routines for squeezing out length- -one dimensions from N-dimensional arrays, ensuring that an array is at -least 1-, 2-, or 3-dimensional, and stacking (concatenating) arrays by -rows, columns, and "pages "(in the third dimension). Routines for -splitting arrays (roughly the opposite of stacking arrays) are also -available. - - -Polynomials -^^^^^^^^^^^ - -There are two (interchangeable) ways to deal with 1-d polynomials in -SciPy. The first is to use the :class:`poly1d` class from Numpy. This -class accepts coefficients or polynomial roots to initialize a -polynomial. The polynomial object can then be manipulated in algebraic -expressions, integrated, differentiated, and evaluated. It even prints -like a polynomial: - - >>> p = poly1d([3,4,5]) - >>> print p - 2 - 3 x + 4 x + 5 - >>> print p*p - 4 3 2 - 9 x + 24 x + 46 x + 40 x + 25 - >>> print p.integ(k=6) - 3 2 - x + 2 x + 5 x + 6 - >>> print p.deriv() - 6 x + 4 - >>> p([4,5]) - array([ 69, 100]) - -The other way to handle polynomials is as an array of coefficients -with the first element of the array giving the coefficient of the -highest power. There are explicit functions to add, subtract, -multiply, divide, integrate, differentiate, and evaluate polynomials -represented as sequences of coefficients. - - -Vectorizing functions (vectorize) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -One of the features that NumPy provides is a class :obj:`vectorize` to -convert an ordinary Python function which accepts scalars and returns -scalars into a "vectorized-function" with the same broadcasting rules -as other Numpy functions (*i.e.* the Universal functions, or -ufuncs). For example, suppose you have a Python function named -:obj:`addsubtract` defined as: - - >>> def addsubtract(a,b): - ... if a > b: - ... return a - b - ... else: - ... return a + b - -which defines a function of two scalar variables and returns a scalar -result. The class vectorize can be used to "vectorize "this function so that :: - - >>> vec_addsubtract = vectorize(addsubtract) - -returns a function which takes array arguments and returns an array -result: - - >>> vec_addsubtract([0,3,6,9],[1,3,5,7]) - array([1, 6, 1, 2]) - -This particular function could have been written in vector form -without the use of :obj:`vectorize` . But, what if the function you have written is the result of some -optimization or integration routine. Such functions can likely only be -vectorized using ``vectorize.`` - - -Other useful functions -^^^^^^^^^^^^^^^^^^^^^^ - -There are several other functions in the scipy_base package including -most of the other functions that are also in the Numpy package. The -reason for duplicating these functions is to allow SciPy to -potentially alter their original interface and make it easier for -users to know how to get access to functions - - >>> from scipy import * - -Functions which should be mentioned are :obj:`mod(x,y)` which can -replace ``x % y`` when it is desired that the result take the sign of -*y* instead of *x* . Also included is :obj:`fix` which always rounds -to the nearest integer towards zero. For doing phase processing, the -functions :func:`angle`, and :obj:`unwrap` are also useful. Also, the -:obj:`linspace` and :obj:`logspace` functions return equally spaced samples -in a linear or log scale. Finally, it's useful to be aware of the indexing -capabilities of Numpy.mention should be made of the new -function :obj:`select` which extends the functionality of :obj:`where` to -include multiple conditions and multiple choices. The calling -convention is ``select(condlist,choicelist,default=0).`` :obj:`select` is -a vectorized form of the multiple if-statement. It allows rapid -construction of a function which returns an array of results based on -a list of conditions. Each element of the return array is taken from -the array in a ``choicelist`` corresponding to the first condition in -``condlist`` that is true. For example - - >>> x = r_[-2:3] - >>> x - array([-2, -1, 0, 1, 2]) - >>> select([x > 3, x >= 0],[0,x+2]) - array([0, 0, 2, 3, 4]) - - -Common functions ----------------- - -Some functions depend on sub-packages of SciPy but should be available -from the top-level of SciPy due to their common use. These are -functions that might have been placed in scipy_base except for their -dependence on other sub-packages of SciPy. For example the -:obj:`factorial` and :obj:`comb` functions compute :math:`n!` and -:math:`n!/k!(n-k)!` using either exact integer arithmetic (thanks to -Python's Long integer object), or by using floating-point precision -and the gamma function. The functions :obj:`rand` and :obj:`randn` -are used so often that they warranted a place at the top level. There -are convenience functions for the interactive use: :obj:`disp` -(similar to print), and :obj:`who` (returns a list of defined -variables and memory consumption--upper bounded). Another function -returns a common image used in image processing: :obj:`lena`. - -Finally, two functions are provided that are useful for approximating -derivatives of functions using discrete-differences. The function -:obj:`central_diff_weights` returns weighting coefficients for an -equally-spaced :math:`N`-point approximation to the derivative of -order *o*. These weights must be multiplied by the function -corresponding to these points and the results added to obtain the -derivative approximation. This function is intended for use when only -samples of the function are avaiable. When the function is an object -that can be handed to a routine and evaluated, the function -:obj:`derivative` can be used to automatically evaluate the object at -the correct points to obtain an N-point approximation to the *o*-th -derivative at a given point. - - -Special functions (:mod:`scipy.special`) -======================================== - -.. currentmodule:: scipy.special - -The main feature of the :mod:`scipy.special` package is the definition of -numerous special functions of mathematical physics. Available -functions include airy, elliptic, bessel, gamma, beta, hypergeometric, -parabolic cylinder, mathieu, spheroidal wave, struve, and -kelvin. There are also some low-level stats functions that are not -intended for general use as an easier interface to these functions is -provided by the ``stats`` module. Most of these functions can take -array arguments and return array results following the same -broadcasting rules as other math functions in Numerical Python. Many -of these functions also accept complex-numbers as input. For a -complete list of the available functions with a one-line description -type ``>>> help(special).`` Each function also has it's own -documentation accessible using help. If you don't see a function you -need, consider writing it and contributing it to the library. You can -write the function in either C, Fortran, or Python. Look in the source -code of the library for examples of each of these kind of functions. - - -Integration (:mod:`scipy.integrate`) -==================================== - -.. currentmodule:: scipy.integrate - -The :mod:`scipy.integrate` sub-package provides several integration -techniques including an ordinary differential equation integrator. An -overview of the module is provided by the help command: - -.. literalinclude:: examples/4-1 - - -General integration (:func:`quad`) ----------------------------------- - -The function :obj:`quad` is provided to integrate a function of one -variable between two points. The points can be :math:`\pm\infty` -(:math:`\pm` ``inf``) to indicate infinite limits. For example, -suppose you wish to integrate a bessel function ``jv(2.5,x)`` along -the interval :math:`[0,4.5].` - -.. math:: - :nowrap: - - \[ I=\int_{0}^{4.5}J_{2.5}\left(x\right)\, dx.\] - -This could be computed using :obj:`quad`: - - >>> result = integrate.quad(lambda x: special.jv(2.5,x), 0, 4.5) - >>> print result - (1.1178179380783249, 7.8663172481899801e-09) - - >>> I = sqrt(2/pi)*(18.0/27*sqrt(2)*cos(4.5)-4.0/27*sqrt(2)*sin(4.5)+ - sqrt(2*pi)*special.fresnel(3/sqrt(pi))[0]) - >>> print I - 1.117817938088701 - - >>> print abs(result[0]-I) - 1.03761443881e-11 - -The first argument to quad is a "callable" Python object (*i.e* a -function, method, or class instance). Notice the use of a lambda- -function in this case as the argument. The next two arguments are the -limits of integration. The return value is a tuple, with the first -element holding the estimated value of the integral and the second -element holding an upper bound on the error. Notice, that in this -case, the true value of this integral is - -.. math:: - :nowrap: - - \[ I=\sqrt{\frac{2}{\pi}}\left(\frac{18}{27}\sqrt{2}\cos\left(4.5\right)-\frac{4}{27}\sqrt{2}\sin\left(4.5\right)+\sqrt{2\pi}\textrm{Si}\left(\frac{3}{\sqrt{\pi}}\right)\right),\] - -where - -.. math:: - :nowrap: - - \[ \textrm{Si}\left(x\right)=\int_{0}^{x}\sin\left(\frac{\pi}{2}t^{2}\right)\, dt.\] - -is the Fresnel sine integral. Note that the numerically-computed -integral is within :math:`1.04\times10^{-11}` of the exact result --- well below the reported error bound. - -Infinite inputs are also allowed in :obj:`quad` by using :math:`\pm` -``inf`` as one of the arguments. For example, suppose that a numerical -value for the exponential integral: - -.. math:: - :nowrap: - - \[ E_{n}\left(x\right)=\int_{1}^{\infty}\frac{e^{-xt}}{t^{n}}\, dt.\] - -is desired (and the fact that this integral can be computed as -``special.expn(n,x)`` is forgotten). The functionality of the function -:obj:`special.expn` can be replicated by defining a new function -:obj:`vec_expint` based on the routine :obj:`quad`: - - >>> from scipy.integrate import quad - >>> def integrand(t,n,x): - ... return exp(-x*t) / t**n - - >>> def expint(n,x): - ... return quad(integrand, 1, Inf, args=(n, x))[0] - - >>> vec_expint = vectorize(expint) - - >>> vec_expint(3,arange(1.0,4.0,0.5)) - array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049]) - >>> special.expn(3,arange(1.0,4.0,0.5)) - array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049]) - -The function which is integrated can even use the quad argument -(though the error bound may underestimate the error due to possible -numerical error in the integrand from the use of :obj:`quad` ). The integral in this case is - -.. math:: - :nowrap: - - \[ I_{n}=\int_{0}^{\infty}\int_{1}^{\infty}\frac{e^{-xt}}{t^{n}}\, dt\, dx=\frac{1}{n}.\] - - >>> result = quad(lambda x: expint(3, x), 0, inf) - >>> print result - (0.33333333324560266, 2.8548934485373678e-09) - - >>> I3 = 1.0/3.0 - >>> print I3 - 0.333333333333 - - >>> print I3 - result[0] - 8.77306560731e-11 - -This last example shows that multiple integration can be handled using -repeated calls to :func:`quad`. The mechanics of this for double and -triple integration have been wrapped up into the functions -:obj:`dblquad` and :obj:`tplquad`. The function, :obj:`dblquad` -performs double integration. Use the help function to be sure that the -arguments are defined in the correct order. In addition, the limits on -all inner integrals are actually functions which can be constant -functions. An example of using double integration to compute several -values of :math:`I_{n}` is shown below: - - >>> from scipy.integrate import quad, dblquad - >>> def I(n): - ... return dblquad(lambda t, x: exp(-x*t)/t**n, 0, Inf, lambda x: 1, lambda x: Inf) - - >>> print I(4) - (0.25000000000435768, 1.0518245707751597e-09) - >>> print I(3) - (0.33333333325010883, 2.8604069919261191e-09) - >>> print I(2) - (0.49999999999857514, 1.8855523253868967e-09) - - -Gaussian quadrature (integrate.gauss_quadtol) ---------------------------------------------- - -A few functions are also provided in order to perform simple Gaussian -quadrature over a fixed interval. The first is :obj:`fixed_quad` which -performs fixed-order Gaussian quadrature. The second function is -:obj:`quadrature` which performs Gaussian quadrature of multiple -orders until the difference in the integral estimate is beneath some -tolerance supplied by the user. These functions both use the module -:mod:`special.orthogonal` which can calculate the roots and quadrature -weights of a large variety of orthogonal polynomials (the polynomials -themselves are available as special functions returning instances of -the polynomial class --- e.g. :obj:`special.legendre `). - - -Integrating using samples -------------------------- - -There are three functions for computing integrals given only samples: -:obj:`trapz` , :obj:`simps`, and :obj:`romb` . The first two -functions use Newton-Coates formulas of order 1 and 2 respectively to -perform integration. These two functions can handle, -non-equally-spaced samples. The trapezoidal rule approximates the -function as a straight line between adjacent points, while Simpson's -rule approximates the function between three adjacent points as a -parabola. - -If the samples are equally-spaced and the number of samples available -is :math:`2^{k}+1` for some integer :math:`k`, then Romberg -integration can be used to obtain high-precision estimates of the -integral using the available samples. Romberg integration uses the -trapezoid rule at step-sizes related by a power of two and then -performs Richardson extrapolation on these estimates to approximate -the integral with a higher-degree of accuracy. (A different interface -to Romberg integration useful when the function can be provided is -also available as :func:`romberg`). - - -Ordinary differential equations (:func:`odeint`) ------------------------------------------------- - -Integrating a set of ordinary differential equations (ODEs) given -initial conditions is another useful example. The function -:obj:`odeint` is available in SciPy for integrating a first-order -vector differential equation: - -.. math:: - :nowrap: - - \[ \frac{d\mathbf{y}}{dt}=\mathbf{f}\left(\mathbf{y},t\right),\] - -given initial conditions :math:`\mathbf{y}\left(0\right)=y_{0}`, where -:math:`\mathbf{y}` is a length :math:`N` vector and :math:`\mathbf{f}` -is a mapping from :math:`\mathcal{R}^{N}` to :math:`\mathcal{R}^{N}.` -A higher-order ordinary differential equation can always be reduced to -a differential equation of this type by introducing intermediate -derivatives into the :math:`\mathbf{y}` vector. - -For example suppose it is desired to find the solution to the -following second-order differential equation: - -.. math:: - :nowrap: - - \[ \frac{d^{2}w}{dz^{2}}-zw(z)=0\] - -with initial conditions :math:`w\left(0\right)=\frac{1}{\sqrt[3]{3^{2}}\Gamma\left(\frac{2}{3}\right)}` and :math:`\left.\frac{dw}{dz}\right|_{z=0}=-\frac{1}{\sqrt[3]{3}\Gamma\left(\frac{1}{3}\right)}.` It is known that the solution to this differential equation with these -boundary conditions is the Airy function - -.. math:: - :nowrap: - - \[ w=\textrm{Ai}\left(z\right),\] - -which gives a means to check the integrator using :func:`special.airy `. - -First, convert this ODE into standard form by setting -:math:`\mathbf{y}=\left[\frac{dw}{dz},w\right]` and :math:`t=z`. Thus, -the differential equation becomes - -.. math:: - :nowrap: - - \[ \frac{d\mathbf{y}}{dt}=\left[\begin{array}{c} ty_{1}\\ y_{0}\end{array}\right]=\left[\begin{array}{cc} 0 & t\\ 1 & 0\end{array}\right]\left[\begin{array}{c} y_{0}\\ y_{1}\end{array}\right]=\left[\begin{array}{cc} 0 & t\\ 1 & 0\end{array}\right]\mathbf{y}.\] - -In other words, - -.. math:: - :nowrap: - - \[ \mathbf{f}\left(\mathbf{y},t\right)=\mathbf{A}\left(t\right)\mathbf{y}.\] - -As an interesting reminder, if :math:`\mathbf{A}\left(t\right)` -commutes with :math:`\int_{0}^{t}\mathbf{A}\left(\tau\right)\, d\tau` -under matrix multiplication, then this linear differential equation -has an exact solution using the matrix exponential: - -.. math:: - :nowrap: - - \[ \mathbf{y}\left(t\right)=\exp\left(\int_{0}^{t}\mathbf{A}\left(\tau\right)d\tau\right)\mathbf{y}\left(0\right),\] - -However, in this case, :math:`\mathbf{A}\left(t\right)` and its integral do not commute. - -There are many optional inputs and outputs available when using odeint -which can help tune the solver. These additional inputs and outputs -are not needed much of the time, however, and the three required input -arguments and the output solution suffice. The required inputs are the -function defining the derivative, *fprime*, the initial conditions -vector, *y0*, and the time points to obtain a solution, *t*, (with -the initial value point as the first element of this sequence). The -output to :obj:`odeint` is a matrix where each row contains the -solution vector at each requested time point (thus, the initial -conditions are given in the first output row). - -The following example illustrates the use of odeint including the -usage of the *Dfun* option which allows the user to specify a gradient -(with respect to :math:`\mathbf{y}` ) of the function, -:math:`\mathbf{f}\left(\mathbf{y},t\right)`. - - >>> from scipy.integrate import odeint - >>> from scipy.special import gamma, airy - >>> y1_0 = 1.0/3**(2.0/3.0)/gamma(2.0/3.0) - >>> y0_0 = -1.0/3**(1.0/3.0)/gamma(1.0/3.0) - >>> y0 = [y0_0, y1_0] - >>> def func(y, t): - ... return [t*y[1],y[0]] - - >>> def gradient(y,t): - ... return [[0,t],[1,0]] - - >>> x = arange(0,4.0, 0.01) - >>> t = x - >>> ychk = airy(x)[0] - >>> y = odeint(func, y0, t) - >>> y2 = odeint(func, y0, t, Dfun=gradient) - - >>> print ychk[:36:6] - [ 0.355028 0.339511 0.324068 0.308763 0.293658 0.278806] - - >>> print y[:36:6,1] - [ 0.355028 0.339511 0.324067 0.308763 0.293658 0.278806] - - >>> print y2[:36:6,1] - [ 0.355028 0.339511 0.324067 0.308763 0.293658 0.278806] - - -Optimization (optimize) -======================= - -.. currentmodule:: scipy.optimize - -There are several classical optimization algorithms provided by SciPy -in the :mod:`scipy.optimize` package. An overview of the module is -available using :func:`help` (or :func:`pydoc.help`): - -.. literalinclude:: examples/5-1 - -The first four algorithms are unconstrained minimization algorithms -(:func:`fmin`: Nelder-Mead simplex, :func:`fmin_bfgs`: BFGS, -:func:`fmin_ncg`: Newton Conjugate Gradient, and :func:`leastsq`: -Levenburg-Marquardt). The last algorithm actually finds the roots of a -general function of possibly many variables. It is included in the -optimization package because at the (non-boundary) extreme points of a -function, the gradient is equal to zero. - - -Nelder-Mead Simplex algorithm (:func:`fmin`) --------------------------------------------- - -The simplex algorithm is probably the simplest way to minimize a -fairly well-behaved function. The simplex algorithm requires only -function evaluations and is a good choice for simple minimization -problems. However, because it does not use any gradient evaluations, -it may take longer to find the minimum. To demonstrate the -minimization function consider the problem of minimizing the -Rosenbrock function of :math:`N` variables: - -.. math:: - :nowrap: - - \[ f\left(\mathbf{x}\right)=\sum_{i=1}^{N-1}100\left(x_{i}-x_{i-1}^{2}\right)^{2}+\left(1-x_{i-1}\right)^{2}.\] - -The minimum value of this function is 0 which is achieved when :math:`x_{i}=1.` This minimum can be found using the :obj:`fmin` routine as shown in the example below: - - >>> from scipy.optimize import fmin - >>> def rosen(x): - ... """The Rosenbrock function""" - ... return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0) - - >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] - >>> xopt = fmin(rosen, x0, xtol=1e-8) - Optimization terminated successfully. - Current function value: 0.000000 - Iterations: 339 - Function evaluations: 571 - - >>> print xopt - [ 1. 1. 1. 1. 1.] - -Another optimization algorithm that needs only function calls to find -the minimum is Powell's method available as :func:`fmin_powell`. - - -Broyden-Fletcher-Goldfarb-Shanno algorithm (:func:`fmin_bfgs`) --------------------------------------------------------------- - -In order to converge more quickly to the solution, this routine uses -the gradient of the objective function. If the gradient is not given -by the user, then it is estimated using first-differences. The -Broyden-Fletcher-Goldfarb-Shanno (BFGS) method typically requires -fewer function calls than the simplex algorithm even when the gradient -must be estimated. - -To demonstrate this algorithm, the Rosenbrock function is again used. -The gradient of the Rosenbrock function is the vector: - -.. math:: - :nowrap: - - \begin{eqnarray*} \frac{\partial f}{\partial x_{j}} & = & \sum_{i=1}^{N}200\left(x_{i}-x_{i-1}^{2}\right)\left(\delta_{i,j}-2x_{i-1}\delta_{i-1,j}\right)-2\left(1-x_{i-1}\right)\delta_{i-1,j}.\\ & = & 200\left(x_{j}-x_{j-1}^{2}\right)-400x_{j}\left(x_{j+1}-x_{j}^{2}\right)-2\left(1-x_{j}\right).\end{eqnarray*} - -This expression is valid for the interior derivatives. Special cases -are - -.. math:: - :nowrap: - - \begin{eqnarray*} \frac{\partial f}{\partial x_{0}} & = & -400x_{0}\left(x_{1}-x_{0}^{2}\right)-2\left(1-x_{0}\right),\\ \frac{\partial f}{\partial x_{N-1}} & = & 200\left(x_{N-1}-x_{N-2}^{2}\right).\end{eqnarray*} - -A Python function which computes this gradient is constructed by the -code-segment: - - >>> def rosen_der(x): - ... xm = x[1:-1] - ... xm_m1 = x[:-2] - ... xm_p1 = x[2:] - ... der = zeros_like(x) - ... der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm) - ... der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0]) - ... der[-1] = 200*(x[-1]-x[-2]**2) - ... return der - -The calling signature for the BFGS minimization algorithm is similar -to :obj:`fmin` with the addition of the *fprime* argument. An example -usage of :obj:`fmin_bfgs` is shown in the following example which -minimizes the Rosenbrock function. - - >>> from scipy.optimize import fmin_bfgs - - >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] - >>> xopt = fmin_bfgs(rosen, x0, fprime=rosen_der) - Optimization terminated successfully. - Current function value: 0.000000 - Iterations: 53 - Function evaluations: 65 - Gradient evaluations: 65 - >>> print xopt - [ 1. 1. 1. 1. 1.] - - -Newton-Conjugate-Gradient (:func:`fmin_ncg`) --------------------------------------------- - -The method which requires the fewest function calls and is therefore -often the fastest method to minimize functions of many variables is -:obj:`fmin_ncg`. This method is a modified Newton's method and uses a -conjugate gradient algorithm to (approximately) invert the local -Hessian. Newton's method is based on fitting the function locally to -a quadratic form: - -.. math:: - :nowrap: - - \[ f\left(\mathbf{x}\right)\approx f\left(\mathbf{x}_{0}\right)+\nabla f\left(\mathbf{x}_{0}\right)\cdot\left(\mathbf{x}-\mathbf{x}_{0}\right)+\frac{1}{2}\left(\mathbf{x}-\mathbf{x}_{0}\right)^{T}\mathbf{H}\left(\mathbf{x}_{0}\right)\left(\mathbf{x}-\mathbf{x}_{0}\right).\] - -where :math:`\mathbf{H}\left(\mathbf{x}_{0}\right)` is a matrix of second-derivatives (the Hessian). If the Hessian is -positive definite then the local minimum of this function can be found -by setting the gradient of the quadratic form to zero, resulting in - -.. math:: - :nowrap: - - \[ \mathbf{x}_{\textrm{opt}}=\mathbf{x}_{0}-\mathbf{H}^{-1}\nabla f.\] - -The inverse of the Hessian is evaluted using the conjugate-gradient -method. An example of employing this method to minimizing the -Rosenbrock function is given below. To take full advantage of the -NewtonCG method, a function which computes the Hessian must be -provided. The Hessian matrix itself does not need to be constructed, -only a vector which is the product of the Hessian with an arbitrary -vector needs to be available to the minimization routine. As a result, -the user can provide either a function to compute the Hessian matrix, -or a function to compute the product of the Hessian with an arbitrary -vector. - - -Full Hessian example: -^^^^^^^^^^^^^^^^^^^^^ - -The Hessian of the Rosenbrock function is - -.. math:: - :nowrap: - - \begin{eqnarray*} H_{ij}=\frac{\partial^{2}f}{\partial x_{i}\partial x_{j}} & = & 200\left(\delta_{i,j}-2x_{i-1}\delta_{i-1,j}\right)-400x_{i}\left(\delta_{i+1,j}-2x_{i}\delta_{i,j}\right)-400\delta_{i,j}\left(x_{i+1}-x_{i}^{2}\right)+2\delta_{i,j},\\ & = & \left(202+1200x_{i}^{2}-400x_{i+1}\right)\delta_{i,j}-400x_{i}\delta_{i+1,j}-400x_{i-1}\delta_{i-1,j},\end{eqnarray*} - -if :math:`i,j\in\left[1,N-2\right]` with :math:`i,j\in\left[0,N-1\right]` defining the :math:`N\times N` matrix. Other non-zero entries of the matrix are - -.. math:: - :nowrap: - - \begin{eqnarray*} \frac{\partial^{2}f}{\partial x_{0}^{2}} & = & 1200x_{0}^{2}-400x_{1}+2,\\ \frac{\partial^{2}f}{\partial x_{0}\partial x_{1}}=\frac{\partial^{2}f}{\partial x_{1}\partial x_{0}} & = & -400x_{0},\\ \frac{\partial^{2}f}{\partial x_{N-1}\partial x_{N-2}}=\frac{\partial^{2}f}{\partial x_{N-2}\partial x_{N-1}} & = & -400x_{N-2},\\ \frac{\partial^{2}f}{\partial x_{N-1}^{2}} & = & 200.\end{eqnarray*} - -For example, the Hessian when :math:`N=5` is - -.. math:: - :nowrap: - - \[ \mathbf{H}=\left[\begin{array}{ccccc} 1200x_{0}^{2}-400x_{1}+2 & -400x_{0} & 0 & 0 & 0\\ -400x_{0} & 202+1200x_{1}^{2}-400x_{2} & -400x_{1} & 0 & 0\\ 0 & -400x_{1} & 202+1200x_{2}^{2}-400x_{3} & -400x_{2} & 0\\ 0 & & -400x_{2} & 202+1200x_{3}^{2}-400x_{4} & -400x_{3}\\ 0 & 0 & 0 & -400x_{3} & 200\end{array}\right].\] - -The code which computes this Hessian along with the code to minimize -the function using :obj:`fmin_ncg` is shown in the following example: - - >>> from scipy.optimize import fmin_ncg - >>> def rosen_hess(x): - ... x = asarray(x) - ... H = diag(-400*x[:-1],1) - diag(400*x[:-1],-1) - ... diagonal = zeros_like(x) - ... diagonal[0] = 1200*x[0]-400*x[1]+2 - ... diagonal[-1] = 200 - ... diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:] - ... H = H + diag(diagonal) - ... return H - - >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] - >>> xopt = fmin_ncg(rosen, x0, rosen_der, fhess=rosen_hess, avextol=1e-8) - Optimization terminated successfully. - Current function value: 0.000000 - Iterations: 23 - Function evaluations: 26 - Gradient evaluations: 23 - Hessian evaluations: 23 - >>> print xopt - [ 1. 1. 1. 1. 1.] - - -Hessian product example: -^^^^^^^^^^^^^^^^^^^^^^^^ - -For larger minimization problems, storing the entire Hessian matrix -can consume considerable time and memory. The Newton-CG algorithm only -needs the product of the Hessian times an arbitrary vector. As a -result, the user can supply code to compute this product rather than -the full Hessian by setting the *fhess_p* keyword to the desired -function. The *fhess_p* function should take the minimization vector as -the first argument and the arbitrary vector as the second -argument. Any extra arguments passed to the function to be minimized -will also be passed to this function. If possible, using Newton-CG -with the hessian product option is probably the fastest way to -minimize the function. - -In this case, the product of the Rosenbrock Hessian with an arbitrary -vector is not difficult to compute. If :math:`\mathbf{p}` is the arbitrary vector, then :math:`\mathbf{H}\left(\mathbf{x}\right)\mathbf{p}` has elements: - -.. math:: - :nowrap: - - \[ \mathbf{H}\left(\mathbf{x}\right)\mathbf{p}=\left[\begin{array}{c} \left(1200x_{0}^{2}-400x_{1}+2\right)p_{0}-400x_{0}p_{1}\\ \vdots\\ -400x_{i-1}p_{i-1}+\left(202+1200x_{i}^{2}-400x_{i+1}\right)p_{i}-400x_{i}p_{i+1}\\ \vdots\\ -400x_{N-2}p_{N-2}+200p_{N-1}\end{array}\right].\] - -Code which makes use of the *fhess_p* keyword to minimize the -Rosenbrock function using :obj:`fmin_ncg` follows: - - >>> from scipy.optimize import fmin_ncg - >>> def rosen_hess_p(x,p): - ... x = asarray(x) - ... Hp = zeros_like(x) - ... Hp[0] = (1200*x[0]**2 - 400*x[1] + 2)*p[0] - 400*x[0]*p[1] - ... Hp[1:-1] = -400*x[:-2]*p[:-2]+(202+1200*x[1:-1]**2-400*x[2:])*p[1:-1] \ - ... -400*x[1:-1]*p[2:] - ... Hp[-1] = -400*x[-2]*p[-2] + 200*p[-1] - ... return Hp - - >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] - >>> xopt = fmin_ncg(rosen, x0, rosen_der, fhess_p=rosen_hess_p, avextol=1e-8) - Optimization terminated successfully. - Current function value: 0.000000 - Iterations: 22 - Function evaluations: 25 - Gradient evaluations: 22 - Hessian evaluations: 54 - >>> print xopt - [ 1. 1. 1. 1. 1.] - - -Least-square fitting (:func:`leastsq`) --------------------------------------- - -All of the previously-explained minimization procedures can be used to -solve a least-squares problem provided the appropriate objective -function is constructed. For example, suppose it is desired to fit a -set of data :math:`\left\{\mathbf{x}_{i}, \mathbf{y}_{i}\right\}` -to a known model, -:math:`\mathbf{y}=\mathbf{f}\left(\mathbf{x},\mathbf{p}\right)` -where :math:`\mathbf{p}` is a vector of parameters for the model that -need to be found. A common method for determining which parameter -vector gives the best fit to the data is to minimize the sum of squares -of the residuals. The residual is usually defined for each observed -data-point as - -.. math:: - :nowrap: - - \[ e_{i}\left(\mathbf{p},\mathbf{y}_{i},\mathbf{x}_{i}\right)=\left\Vert \mathbf{y}_{i}-\mathbf{f}\left(\mathbf{x}_{i},\mathbf{p}\right)\right\Vert .\] - -An objective function to pass to any of the previous minization -algorithms to obtain a least-squares fit is. - -.. math:: - :nowrap: - - \[ J\left(\mathbf{p}\right)=\sum_{i=0}^{N-1}e_{i}^{2}\left(\mathbf{p}\right).\] - - - -The :obj:`leastsq` algorithm performs this squaring and summing of the -residuals automatically. It takes as an input argument the vector -function :math:`\mathbf{e}\left(\mathbf{p}\right)` and returns the -value of :math:`\mathbf{p}` which minimizes -:math:`J\left(\mathbf{p}\right)=\mathbf{e}^{T}\mathbf{e}` -directly. The user is also encouraged to provide the Jacobian matrix -of the function (with derivatives down the columns or across the -rows). If the Jacobian is not provided, it is estimated. - -An example should clarify the usage. Suppose it is believed some -measured data follow a sinusoidal pattern - -.. math:: - :nowrap: - - \[ y_{i}=A\sin\left(2\pi kx_{i}+\theta\right)\] - -where the parameters :math:`A,` :math:`k` , and :math:`\theta` are unknown. The residual vector is - -.. math:: - :nowrap: - - \[ e_{i}=\left|y_{i}-A\sin\left(2\pi kx_{i}+\theta\right)\right|.\] - -By defining a function to compute the residuals and (selecting an -appropriate starting position), the least-squares fit routine can be -used to find the best-fit parameters :math:`\hat{A},\,\hat{k},\,\hat{\theta}`. -This is shown in the following example: - -.. plot:: - - >>> from numpy import * - >>> x = arange(0,6e-2,6e-2/30) - >>> A,k,theta = 10, 1.0/3e-2, pi/6 - >>> y_true = A*sin(2*pi*k*x+theta) - >>> y_meas = y_true + 2*random.randn(len(x)) - - >>> def residuals(p, y, x): - ... A,k,theta = p - ... err = y-A*sin(2*pi*k*x+theta) - ... return err - - >>> def peval(x, p): - ... return p[0]*sin(2*pi*p[1]*x+p[2]) - - >>> p0 = [8, 1/2.3e-2, pi/3] - >>> print array(p0) - [ 8. 43.4783 1.0472] - - >>> from scipy.optimize import leastsq - >>> plsq = leastsq(residuals, p0, args=(y_meas, x)) - >>> print plsq[0] - [ 10.9437 33.3605 0.5834] - - >>> print array([A, k, theta]) - [ 10. 33.3333 0.5236] - - >>> import matplotlib.pyplot as plt - >>> plt.plot(x,peval(x,plsq[0]),x,y_meas,'o',x,y_true) - >>> plt.title('Least-squares fit to noisy data') - >>> plt.legend(['Fit', 'Noisy', 'True']) - >>> plt.show() - -.. :caption: Least-square fitting to noisy data using -.. :obj:`scipy.optimize.leastsq` - - -Scalar function minimizers --------------------------- - -Often only the minimum of a scalar function is needed (a scalar -function is one that takes a scalar as input and returns a scalar -output). In these circumstances, other optimization techniques have -been developed that can work faster. - - -Unconstrained minimization (:func:`brent`) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -There are actually two methods that can be used to minimize a scalar -function (:obj:`brent` and :func:`golden`), but :obj:`golden` is -included only for academic purposes and should rarely be used. The -brent method uses Brent's algorithm for locating a minimum. Optimally -a bracket should be given which contains the minimum desired. A -bracket is a triple :math:`\left(a,b,c\right)` such that -:math:`f\left(a\right)>f\left(b\right)>> from scipy.special import j1 - >>> from scipy.optimize import fminbound - >>> xmin = fminbound(j1, 4, 7) - >>> print xmin - 5.33144184241 - - -Root finding ------------- - - -Sets of equations -^^^^^^^^^^^^^^^^^ - -To find the roots of a polynomial, the command :obj:`roots -` is useful. To find a root of a set of non-linear -equations, the command :obj:`fsolve` is needed. For example, the -following example finds the roots of the single-variable -transcendental equation - -.. math:: - :nowrap: - - \[ x+2\cos\left(x\right)=0,\] - -and the set of non-linear equations - -.. math:: - :nowrap: - - \begin{eqnarray*} x_{0}\cos\left(x_{1}\right) & = & 4,\\ x_{0}x_{1}-x_{1} & = & 5.\end{eqnarray*} - -The results are :math:`x=-1.0299` and :math:`x_{0}=6.5041,\, x_{1}=0.9084` . - - >>> def func(x): - ... return x + 2*cos(x) - - >>> def func2(x): - ... out = [x[0]*cos(x[1]) - 4] - ... out.append(x[1]*x[0] - x[1] - 5) - ... return out - - >>> from scipy.optimize import fsolve - >>> x0 = fsolve(func, 0.3) - >>> print x0 - -1.02986652932 - - >>> x02 = fsolve(func2, [1, 1]) - >>> print x02 - [ 6.50409711 0.90841421] - - - -Scalar function root finding -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If one has a single-variable equation, there are four different root -finder algorithms that can be tried. Each of these root finding -algorithms requires the endpoints of an interval where a root is -suspected (because the function changes signs). In general -:obj:`brentq` is the best choice, but the other methods may be useful -in certain circumstances or for academic purposes. - - -Fixed-point solving -^^^^^^^^^^^^^^^^^^^ - -A problem closely related to finding the zeros of a function is the -problem of finding a fixed-point of a function. A fixed point of a -function is the point at which evaluation of the function returns the -point: :math:`g\left(x\right)=x.` Clearly the fixed point of :math:`g` -is the root of :math:`f\left(x\right)=g\left(x\right)-x.` -Equivalently, the root of :math:`f` is the fixed_point of -:math:`g\left(x\right)=f\left(x\right)+x.` The routine -:obj:`fixed_point` provides a simple iterative method using Aitkens -sequence acceleration to estimate the fixed point of :math:`g` given a -starting point. - - -Interpolation (:mod:`scipy.interpolate`) -======================================== - -.. currentmodule:: scipy.interpolate - -There are two general interpolation facilities available in SciPy. The -first facility is an interpolation class which performs linear -1-dimensional interpolation. The second facility is based on the -FORTRAN library FITPACK and provides functions for 1- and -2-dimensional (smoothed) cubic-spline interpolation. - - -Linear 1-d interpolation (:class:`interp1d`) --------------------------------------------- - -The interp1d class in scipy.interpolate is a convenient method to -create a function based on fixed data points which can be evaluated -anywhere within the domain defined by the given data using linear -interpolation. An instance of this class is created by passing the 1-d -vectors comprising the data. The instance of this class defines a -:meth:`__call__ ` method and can therefore by -treated like a function which interpolates between known data values -to obtain unknown values (it also has a docstring for help). Behavior -at the boundary can be specified at instantiation time. The following -example demonstrates it's use. - -.. plot:: - - >>> from numpy import * - >>> from scipy import interpolate - - >>> x = arange(0,10) - >>> y = exp(-x/3.0) - >>> f = interpolate.interp1d(x, y) - - >>> xnew = arange(0,9,0.1) - >>> import matplotlib.pyplot as plt - >>> plt.plot(x,y,'o',xnew,f(xnew),'-') - -.. :caption: One-dimensional interpolation using the -.. class :obj:`interpolate.interp1d` - - -Spline interpolation in 1-d (interpolate.splXXX) ------------------------------------------------- - -Spline interpolation requires two essential steps: (1) a spline -representation of the curve is computed, and (2) the spline is -evaluated at the desired points. In order to find the spline -representation, there are two different was to represent a curve and -obtain (smoothing) spline coefficients: directly and parametrically. -The direct method finds the spline representation of a curve in a two- -dimensional plane using the function :obj:`splrep`. The -first two arguments are the only ones required, and these provide the -:math:`x` and :math:`y` components of the curve. The normal output is -a 3-tuple, :math:`\left(t,c,k\right)` , containing the knot-points, -:math:`t` , the coefficients :math:`c` and the order :math:`k` of the -spline. The default spline order is cubic, but this can be changed -with the input keyword, *k.* - -For curves in :math:`N` -dimensional space the function -:obj:`splprep` allows defining the curve -parametrically. For this function only 1 input argument is -required. This input is a list of :math:`N` -arrays representing the -curve in :math:`N` -dimensional space. The length of each array is the -number of curve points, and each array provides one component of the -:math:`N` -dimensional data point. The parameter variable is given -with the keword argument, *u,* which defaults to an equally-spaced -monotonic sequence between :math:`0` and :math:`1` . The default -output consists of two objects: a 3-tuple, :math:`\left(t,c,k\right)` -, containing the spline representation and the parameter variable -:math:`u.` - -The keyword argument, *s* , is used to specify the amount of smoothing -to perform during the spline fit. The default value of :math:`s` is -:math:`s=m-\sqrt{2m}` where :math:`m` is the number of data-points -being fit. Therefore, **if no smoothing is desired a value of** -:math:`\mathbf{s}=0` **should be passed to the routines.** - -Once the spline representation of the data has been determined, -functions are available for evaluating the spline -(:func:`splev`) and its derivatives -(:func:`splev`, :func:`splade`) at any point -and the integral of the spline between any two points ( -:func:`splint`). In addition, for cubic splines ( :math:`k=3` -) with 8 or more knots, the roots of the spline can be estimated ( -:func:`sproot`). These functions are demonstrated in the -example that follows. - -.. plot:: - - >>> from numpy import * - >>> import matplotlib.pyplot as plt - >>> from scipy import interpolate - - Cubic-spline - - >>> x = arange(0,2*pi+pi/4,2*pi/8) - >>> y = sin(x) - >>> tck = interpolate.splrep(x,y,s=0) - >>> xnew = arange(0,2*pi,pi/50) - >>> ynew = interpolate.splev(xnew,tck,der=0) - - >>> plt.figure() - >>> plt.plot(x,y,'x',xnew,ynew,xnew,sin(xnew),x,y,'b') - >>> plt.legend(['Linear','Cubic Spline', 'True']) - >>> plt.axis([-0.05,6.33,-1.05,1.05]) - >>> plt.title('Cubic-spline interpolation') - >>> plt.show() - - Derivative of spline - - >>> yder = interpolate.splev(xnew,tck,der=1) - >>> plt.figure() - >>> plt.plot(xnew,yder,xnew,cos(xnew),'--') - >>> plt.legend(['Cubic Spline', 'True']) - >>> plt.axis([-0.05,6.33,-1.05,1.05]) - >>> plt.title('Derivative estimation from spline') - >>> plt.show() - - Integral of spline - - >>> def integ(x,tck,constant=-1): - >>> x = atleast_1d(x) - >>> out = zeros(x.shape, dtype=x.dtype) - >>> for n in xrange(len(out)): - >>> out[n] = interpolate.splint(0,x[n],tck) - >>> out += constant - >>> return out - >>> - >>> yint = integ(xnew,tck) - >>> plt.figure() - >>> plt.plot(xnew,yint,xnew,-cos(xnew),'--') - >>> plt.legend(['Cubic Spline', 'True']) - >>> plt.axis([-0.05,6.33,-1.05,1.05]) - >>> plt.title('Integral estimation from spline') - >>> plt.show() - - Roots of spline - - >>> print interpolate.sproot(tck) - [ 0. 3.1416] - - Parametric spline - - >>> t = arange(0,1.1,.1) - >>> x = sin(2*pi*t) - >>> y = cos(2*pi*t) - >>> tck,u = interpolate.splprep([x,y],s=0) - >>> unew = arange(0,1.01,0.01) - >>> out = interpolate.splev(unew,tck) - >>> plt.figure() - >>> plt.plot(x,y,'x',out[0],out[1],sin(2*pi*unew),cos(2*pi*unew),x,y,'b') - >>> plt.legend(['Linear','Cubic Spline', 'True']) - >>> plt.axis([-1.05,1.05,-1.05,1.05]) - >>> plt.title('Spline of parametrically-defined curve') - >>> plt.show() - - -Two-dimensional spline representation (:func:`bisplrep`) --------------------------------------------------------- - -For (smooth) spline-fitting to a two dimensional surface, the function -:func:`bisplrep` is available. This function takes as required inputs -the **1-D** arrays *x*, *y*, and *z* which represent points on the -surface :math:`z=f\left(x,y\right).` The default output is a list -:math:`\left[tx,ty,c,kx,ky\right]` whose entries represent -respectively, the components of the knot positions, the coefficients -of the spline, and the order of the spline in each coordinate. It is -convenient to hold this list in a single object, *tck,* so that it can -be passed easily to the function :obj:`bisplev`. The -keyword, *s* , can be used to change the amount of smoothing performed -on the data while determining the appropriate spline. The default -value is :math:`s=m-\sqrt{2m}` where :math:`m` is the number of data -points in the *x, y,* and *z* vectors. As a result, if no smoothing is -desired, then :math:`s=0` should be passed to -:obj:`bisplrep` . - -To evaluate the two-dimensional spline and it's partial derivatives -(up to the order of the spline), the function -:obj:`bisplev` is required. This function takes as the -first two arguments **two 1-D arrays** whose cross-product specifies -the domain over which to evaluate the spline. The third argument is -the *tck* list returned from :obj:`bisplrep`. If desired, -the fourth and fifth arguments provide the orders of the partial -derivative in the :math:`x` and :math:`y` direction respectively. - -It is important to note that two dimensional interpolation should not -be used to find the spline representation of images. The algorithm -used is not amenable to large numbers of input points. The signal -processing toolbox contains more appropriate algorithms for finding -the spline representation of an image. The two dimensional -interpolation commands are intended for use when interpolating a two -dimensional function as shown in the example that follows. This -example uses the :obj:`mgrid ` command in SciPy which is -useful for defining a "mesh-grid "in many dimensions. (See also the -:obj:`ogrid ` command if the full-mesh is not -needed). The number of output arguments and the number of dimensions -of each argument is determined by the number of indexing objects -passed in :obj:`mgrid `[]. - -.. plot:: - - >>> from numpy import * - >>> from scipy import interpolate - >>> import matplotlib.pyplot as plt - - Define function over sparse 20x20 grid - - >>> x,y = mgrid[-1:1:20j,-1:1:20j] - >>> z = (x+y)*exp(-6.0*(x*x+y*y)) - - >>> plt.figure() - >>> plt.pcolor(x,y,z) - >>> plt.colorbar() - >>> plt.title("Sparsely sampled function.") - >>> plt.show() - - Interpolate function over new 70x70 grid - - >>> xnew,ynew = mgrid[-1:1:70j,-1:1:70j] - >>> tck = interpolate.bisplrep(x,y,z,s=0) - >>> znew = interpolate.bisplev(xnew[:,0],ynew[0,:],tck) - - >>> plt.figure() - >>> plt.pcolor(xnew,ynew,znew) - >>> plt.colorbar() - >>> plt.title("Interpolated function.") - >>> plt.show() - -.. :caption: Example of two-dimensional spline interpolation. - - -Signal Processing (signal) -========================== - -The signal processing toolbox currently contains some filtering -functions, a limited set of filter design tools, and a few B-spline -interpolation algorithms for one- and two-dimensional data. While the -B-spline algorithms could technically be placed under the -interpolation category, they are included here because they only work -with equally-spaced data and make heavy use of filter-theory and -transfer-function formalism to provide a fast B-spline transform. To -understand this section you will need to understand that a signal in -SciPy is an array of real or complex numbers. - - -B-splines ---------- - -A B-spline is an approximation of a continuous function over a finite- -domain in terms of B-spline coefficients and knot points. If the knot- -points are equally spaced with spacing :math:`\Delta x` , then the B-spline approximation to a 1-dimensional function is the -finite-basis expansion. - -.. math:: - :nowrap: - - \[ y\left(x\right)\approx\sum_{j}c_{j}\beta^{o}\left(\frac{x}{\Delta x}-j\right).\] - -In two dimensions with knot-spacing :math:`\Delta x` and :math:`\Delta y` , the function representation is - -.. math:: - :nowrap: - - \[ z\left(x,y\right)\approx\sum_{j}\sum_{k}c_{jk}\beta^{o}\left(\frac{x}{\Delta x}-j\right)\beta^{o}\left(\frac{y}{\Delta y}-k\right).\] - -In these expressions, :math:`\beta^{o}\left(\cdot\right)` is the space-limited B-spline basis function of order, :math:`o` . The requirement of equally-spaced knot-points and equally-spaced -data points, allows the development of fast (inverse-filtering) -algorithms for determining the coefficients, :math:`c_{j}` , from sample-values, :math:`y_{n}` . Unlike the general spline interpolation algorithms, these algorithms -can quickly find the spline coefficients for large images. - -The advantage of representing a set of samples via B-spline basis -functions is that continuous-domain operators (derivatives, re- -sampling, integral, etc.) which assume that the data samples are drawn -from an underlying continuous function can be computed with relative -ease from the spline coefficients. For example, the second-derivative -of a spline is - -.. math:: - :nowrap: - - \[ y{}^{\prime\prime}\left(x\right)=\frac{1}{\Delta x^{2}}\sum_{j}c_{j}\beta^{o\prime\prime}\left(\frac{x}{\Delta x}-j\right).\] - -Using the property of B-splines that - -.. math:: - :nowrap: - - \[ \frac{d^{2}\beta^{o}\left(w\right)}{dw^{2}}=\beta^{o-2}\left(w+1\right)-2\beta^{o-2}\left(w\right)+\beta^{o-2}\left(w-1\right)\] - -it can be seen that - -.. math:: - :nowrap: - - \[ y^{\prime\prime}\left(x\right)=\frac{1}{\Delta x^{2}}\sum_{j}c_{j}\left[\beta^{o-2}\left(\frac{x}{\Delta x}-j+1\right)-2\beta^{o-2}\left(\frac{x}{\Delta x}-j\right)+\beta^{o-2}\left(\frac{x}{\Delta x}-j-1\right)\right].\] - -If :math:`o=3` , then at the sample points, - -.. math:: - :nowrap: - - \begin{eqnarray*} \Delta x^{2}\left.y^{\prime}\left(x\right)\right|_{x=n\Delta x} & = & \sum_{j}c_{j}\delta_{n-j+1}-2c_{j}\delta_{n-j}+c_{j}\delta_{n-j-1},\\ & = & c_{n+1}-2c_{n}+c_{n-1}.\end{eqnarray*} - -Thus, the second-derivative signal can be easily calculated from the -spline fit. if desired, smoothing splines can be found to make the -second-derivative less sensitive to random-errors. - -The savvy reader will have already noticed that the data samples are -related to the knot coefficients via a convolution operator, so that -simple convolution with the sampled B-spline function recovers the -original data from the spline coefficients. The output of convolutions -can change depending on how boundaries are handled (this becomes -increasingly more important as the number of dimensions in the data- -set increases). The algorithms relating to B-splines in the signal- -processing sub package assume mirror-symmetric boundary conditions. -Thus, spline coefficients are computed based on that assumption, and -data-samples can be recovered exactly from the spline coefficients by -assuming them to be mirror-symmetric also. - -Currently the package provides functions for determining second- and -third-order cubic spline coefficients from equally spaced samples in -one- and two-dimensions (:func:`signal.qspline1d`, -:func:`signal.qspline2d`, :func:`signal.cspline1d`, -:func:`signal.cspline2d`). The package also supplies a function ( -:obj:`signal.bspline` ) for evaluating the bspline basis function, -:math:`\beta^{o}\left(x\right)` for arbitrary order and :math:`x.` For -large :math:`o` , the B-spline basis function can be approximated well -by a zero-mean Gaussian function with standard-deviation equal to -:math:`\sigma_{o}=\left(o+1\right)/12` : - -.. math:: - :nowrap: - - \[ \beta^{o}\left(x\right)\approx\frac{1}{\sqrt{2\pi\sigma_{o}^{2}}}\exp\left(-\frac{x^{2}}{2\sigma_{o}}\right).\] - -A function to compute this Gaussian for arbitrary :math:`x` and -:math:`o` is also available ( :obj:`signal.gauss_spline` ). The -following code and Figure uses spline-filtering to compute an -edge-image (the second-derivative of a smoothed spline) of Lena's face -which is an array returned by the command :func:`lena`. The command -:obj:`signal.sepfir2d` was used to apply a separable two-dimensional -FIR filter with mirror- symmetric boundary conditions to the spline -coefficients. This function is ideally suited for reconstructing -samples from spline coefficients and is faster than -:obj:`signal.convolve2d` which convolves arbitrary two-dimensional -filters and allows for choosing mirror-symmetric boundary conditions. - -.. plot:: - - >>> from numpy import * - >>> from scipy import signal, misc - >>> import matplotlib.pyplot as plt - - >>> image = misc.lena().astype(float32) - >>> derfilt = array([1.0,-2,1.0],float32) - >>> ck = signal.cspline2d(image,8.0) - >>> deriv = signal.sepfir2d(ck, derfilt, [1]) + \ - >>> signal.sepfir2d(ck, [1], derfilt) - - Alternatively we could have done:: - - laplacian = array([[0,1,0],[1,-4,1],[0,1,0]],float32) - deriv2 = signal.convolve2d(ck,laplacian,mode='same',boundary='symm') - - >>> plt.figure() - >>> plt.imshow(image) - >>> plt.gray() - >>> plt.title('Original image') - >>> plt.show() - - >>> plt.figure() - >>> plt.imshow(deriv) - >>> plt.gray() - >>> plt.title('Output of spline edge filter') - >>> plt.show() - -.. :caption: Example of using smoothing splines to filter images. - - -Filtering ---------- - -Filtering is a generic name for any system that modifies an input -signal in some way. In SciPy a signal can be thought of as a Numpy -array. There are different kinds of filters for different kinds of -operations. There are two broad kinds of filtering operations: linear -and non-linear. Linear filters can always be reduced to multiplication -of the flattened Numpy array by an appropriate matrix resulting in -another flattened Numpy array. Of course, this is not usually the best -way to compute the filter as the matrices and vectors involved may be -huge. For example filtering a :math:`512\times512` image with this -method would require multiplication of a :math:`512^{2}x512^{2}` -matrix with a :math:`512^{2}` vector. Just trying to store the -:math:`512^{2}\times512^{2}` matrix using a standard Numpy array would -require :math:`68,719,476,736` elements. At 4 bytes per element this -would require :math:`256\textrm{GB}` of memory. In most applications -most of the elements of this matrix are zero and a different method -for computing the output of the filter is employed. - - -Convolution/Correlation -^^^^^^^^^^^^^^^^^^^^^^^ - -Many linear filters also have the property of shift-invariance. This -means that the filtering operation is the same at different locations -in the signal and it implies that the filtering matrix can be -constructed from knowledge of one row (or column) of the matrix alone. -In this case, the matrix multiplication can be accomplished using -Fourier transforms. - -Let :math:`x\left[n\right]` define a one-dimensional signal indexed by the integer :math:`n.` Full convolution of two one-dimensional signals can be expressed as - -.. math:: - :nowrap: - - \[ y\left[n\right]=\sum_{k=-\infty}^{\infty}x\left[k\right]h\left[n-k\right].\] - -This equation can only be implemented directly if we limit the -sequences to finite support sequences that can be stored in a -computer, choose :math:`n=0` to be the starting point of both -sequences, let :math:`K+1` be that value for which -:math:`y\left[n\right]=0` for all :math:`n>K+1` and :math:`M+1` be -that value for which :math:`x\left[n\right]=0` for all :math:`n>M+1` , -then the discrete convolution expression is - -.. math:: - :nowrap: - - \[ y\left[n\right]=\sum_{k=\max\left(n-M,0\right)}^{\min\left(n,K\right)}x\left[k\right]h\left[n-k\right].\] - -For convenience assume :math:`K\geq M.` Then, more explicitly the output of this operation is - -.. math:: - :nowrap: - - \begin{eqnarray*} y\left[0\right] & = & x\left[0\right]h\left[0\right]\\ y\left[1\right] & = & x\left[0\right]h\left[1\right]+x\left[1\right]h\left[0\right]\\ y\left[2\right] & = & x\left[0\right]h\left[2\right]+x\left[1\right]h\left[1\right]+x\left[2\right]h\left[0\right]\\ \vdots & \vdots & \vdots\\ y\left[M\right] & = & x\left[0\right]h\left[M\right]+x\left[1\right]h\left[M-1\right]+\cdots+x\left[M\right]h\left[0\right]\\ y\left[M+1\right] & = & x\left[1\right]h\left[M\right]+x\left[2\right]h\left[M-1\right]+\cdots+x\left[M+1\right]h\left[0\right]\\ \vdots & \vdots & \vdots\\ y\left[K\right] & = & x\left[K-M\right]h\left[M\right]+\cdots+x\left[K\right]h\left[0\right]\\ y\left[K+1\right] & = & x\left[K+1-M\right]h\left[M\right]+\cdots+x\left[K\right]h\left[1\right]\\ \vdots & \vdots & \vdots\\ y\left[K+M-1\right] & = & x\left[K-1\right]h\left[M\right]+x\left[K\right]h\left[M-1\right]\\ y\left[K+M\right] & = & x\left[K\right]h\left[M\right].\end{eqnarray*} - -Thus, the full discrete convolution of two finite sequences of lengths :math:`K+1` and :math:`M+1` respectively results in a finite sequence of length :math:`K+M+1=\left(K+1\right)+\left(M+1\right)-1.` - -One dimensional convolution is implemented in SciPy with the function -``signal.convolve`` . This function takes as inputs the signals -:math:`x,` :math:`h` , and an optional flag and returns the signal -:math:`y.` The optional flag allows for specification of which part of -the output signal to return. The default value of 'full' returns the -entire signal. If the flag has a value of 'same' then only the middle -:math:`K` values are returned starting at :math:`y\left[\left\lfloor -\frac{M-1}{2}\right\rfloor \right]` so that the output has the same -length as the largest input. If the flag has a value of 'valid' then -only the middle :math:`K-M+1=\left(K+1\right)-\left(M+1\right)+1` -output values are returned where :math:`z` depends on all of the -values of the smallest input from :math:`h\left[0\right]` to -:math:`h\left[M\right].` In other words only the values -:math:`y\left[M\right]` to :math:`y\left[K\right]` inclusive are -returned. - -This same function ``signal.convolve`` can actually take :math:`N` --dimensional arrays as inputs and will return the :math:`N` --dimensional convolution of the two arrays. The same input flags are -available for that case as well. - -Correlation is very similar to convolution except for the minus sign -becomes a plus sign. Thus - -.. math:: - :nowrap: - - \[ w\left[n\right]=\sum_{k=-\infty}^{\infty}y\left[k\right]x\left[n+k\right]\] - -is the (cross) correlation of the signals :math:`y` and :math:`x.` For finite-length signals with :math:`y\left[n\right]=0` outside of the range :math:`\left[0,K\right]` and :math:`x\left[n\right]=0` outside of the range :math:`\left[0,M\right],` the summation can simplify to - -.. math:: - :nowrap: - - \[ w\left[n\right]=\sum_{k=\max\left(0,-n\right)}^{\min\left(K,M-n\right)}y\left[k\right]x\left[n+k\right].\] - -Assuming again that :math:`K\geq M` this is - -.. math:: - :nowrap: - - \begin{eqnarray*} w\left[-K\right] & = & y\left[K\right]x\left[0\right]\\ w\left[-K+1\right] & = & y\left[K-1\right]x\left[0\right]+y\left[K\right]x\left[1\right]\\ \vdots & \vdots & \vdots\\ w\left[M-K\right] & = & y\left[K-M\right]x\left[0\right]+y\left[K-M+1\right]x\left[1\right]+\cdots+y\left[K\right]x\left[M\right]\\ w\left[M-K+1\right] & = & y\left[K-M-1\right]x\left[0\right]+\cdots+y\left[K-1\right]x\left[M\right]\\ \vdots & \vdots & \vdots\\ w\left[-1\right] & = & y\left[1\right]x\left[0\right]+y\left[2\right]x\left[1\right]+\cdots+y\left[M+1\right]x\left[M\right]\\ w\left[0\right] & = & y\left[0\right]x\left[0\right]+y\left[1\right]x\left[1\right]+\cdots+y\left[M\right]x\left[M\right]\\ w\left[1\right] & = & y\left[0\right]x\left[1\right]+y\left[1\right]x\left[2\right]+\cdots+y\left[M-1\right]x\left[M\right]\\ w\left[2\right] & = & y\left[0\right]x\left[2\right]+y\left[1\right]x\left[3\right]+\cdots+y\left[M-2\right]x\left[M\right]\\ \vdots & \vdots & \vdots\\ w\left[M-1\right] & = & y\left[0\right]x\left[M-1\right]+y\left[1\right]x\left[M\right]\\ w\left[M\right] & = & y\left[0\right]x\left[M\right].\end{eqnarray*} - - - -The SciPy function ``signal.correlate`` implements this -operation. Equivalent flags are available for this operation to return -the full :math:`K+M+1` length sequence ('full') or a sequence with the -same size as the largest sequence starting at -:math:`w\left[-K+\left\lfloor \frac{M-1}{2}\right\rfloor \right]` -('same') or a sequence where the values depend on all the values of -the smallest sequence ('valid'). This final option returns the -:math:`K-M+1` values :math:`w\left[M-K\right]` to -:math:`w\left[0\right]` inclusive. - -The function :obj:`signal.correlate` can also take arbitrary :math:`N` --dimensional arrays as input and return the :math:`N` -dimensional -convolution of the two arrays on output. - -When :math:`N=2,` :obj:`signal.correlate` and/or -:obj:`signal.convolve` can be used to construct arbitrary image -filters to perform actions such as blurring, enhancing, and -edge-detection for an image. - -Convolution is mainly used for filtering when one of the signals is -much smaller than the other ( :math:`K\gg M` ), otherwise linear -filtering is more easily accomplished in the frequency domain (see -Fourier Transforms). - - -Difference-equation filtering -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -A general class of linear one-dimensional filters (that includes -convolution filters) are filters described by the difference equation - -.. math:: - :nowrap: - - \[ \sum_{k=0}^{N}a_{k}y\left[n-k\right]=\sum_{k=0}^{M}b_{k}x\left[n-k\right]\] - -where :math:`x\left[n\right]` is the input sequence and -:math:`y\left[n\right]` is the output sequence. If we assume initial -rest so that :math:`y\left[n\right]=0` for :math:`n<0` , then this -kind of filter can be implemented using convolution. However, the -convolution filter sequence :math:`h\left[n\right]` could be infinite -if :math:`a_{k}\neq0` for :math:`k\geq1.` In addition, this general -class of linear filter allows initial conditions to be placed on -:math:`y\left[n\right]` for :math:`n<0` resulting in a filter that -cannot be expressed using convolution. - -The difference equation filter can be thought of as finding :math:`y\left[n\right]` recursively in terms of it's previous values - -.. math:: - :nowrap: - - \[ a_{0}y\left[n\right]=-a_{1}y\left[n-1\right]-\cdots-a_{N}y\left[n-N\right]+\cdots+b_{0}x\left[n\right]+\cdots+b_{M}x\left[n-M\right].\] - -Often :math:`a_{0}=1` is chosen for normalization. The implementation -in SciPy of this general difference equation filter is a little more -complicated then would be implied by the previous equation. It is -implemented so that only one signal needs to be delayed. The actual -implementation equations are (assuming :math:`a_{0}=1` ). - -.. math:: - :nowrap: - - \begin{eqnarray*} y\left[n\right] & = & b_{0}x\left[n\right]+z_{0}\left[n-1\right]\\ z_{0}\left[n\right] & = & b_{1}x\left[n\right]+z_{1}\left[n-1\right]-a_{1}y\left[n\right]\\ z_{1}\left[n\right] & = & b_{2}x\left[n\right]+z_{2}\left[n-1\right]-a_{2}y\left[n\right]\\ \vdots & \vdots & \vdots\\ z_{K-2}\left[n\right] & = & b_{K-1}x\left[n\right]+z_{K-1}\left[n-1\right]-a_{K-1}y\left[n\right]\\ z_{K-1}\left[n\right] & = & b_{K}x\left[n\right]-a_{K}y\left[n\right],\end{eqnarray*} - -where :math:`K=\max\left(N,M\right).` Note that :math:`b_{K}=0` if -:math:`K>M` and :math:`a_{K}=0` if :math:`K>N.` In this way, the -output at time :math:`n` depends only on the input at time :math:`n` -and the value of :math:`z_{0}` at the previous time. This can always -be calculated as long as the :math:`K` values -:math:`z_{0}\left[n-1\right]\ldots z_{K-1}\left[n-1\right]` are -computed and stored at each time step. - -The difference-equation filter is called using the command -:obj:`signal.lfilter` in SciPy. This command takes as inputs the -vector :math:`b,` the vector, :math:`a,` a signal :math:`x` and -returns the vector :math:`y` (the same length as :math:`x` ) computed -using the equation given above. If :math:`x` is :math:`N` --dimensional, then the filter is computed along the axis provided. If, -desired, initial conditions providing the values of -:math:`z_{0}\left[-1\right]` to :math:`z_{K-1}\left[-1\right]` can be -provided or else it will be assumed that they are all zero. If initial -conditions are provided, then the final conditions on the intermediate -variables are also returned. These could be used, for example, to -restart the calculation in the same state. - -Sometimes it is more convenient to express the initial conditions in -terms of the signals :math:`x\left[n\right]` and -:math:`y\left[n\right].` In other words, perhaps you have the values -of :math:`x\left[-M\right]` to :math:`x\left[-1\right]` and the values -of :math:`y\left[-N\right]` to :math:`y\left[-1\right]` and would like -to determine what values of :math:`z_{m}\left[-1\right]` should be -delivered as initial conditions to the difference-equation filter. It -is not difficult to show that for :math:`0\leq m`. If you are going to be doing a lot of matrix-math, it -is convenient to convert arrays into matrices using this command. One -advantage of using the :func:`mat` command is that you can enter -two-dimensional matrices using MATLAB-like syntax with commas or -spaces separating columns and semicolons separting rows as long as the -matrix is placed in a string passed to :obj:`mat` . - - -Basic routines --------------- - - -Finding Inverse -^^^^^^^^^^^^^^^ - -The inverse of a matrix :math:`\mathbf{A}` is the matrix -:math:`\mathbf{B}` such that :math:`\mathbf{AB}=\mathbf{I}` where -:math:`\mathbf{I}` is the identity matrix consisting of ones down the -main diagonal. Usually :math:`\mathbf{B}` is denoted -:math:`\mathbf{B}=\mathbf{A}^{-1}` . In SciPy, the matrix inverse of -the Numpy array, A, is obtained using :obj:`linalg.inv` ``(A)`` , or -using ``A.I`` if ``A`` is a Matrix. For example, let - -.. math:: - :nowrap: - - \[ \mathbf{A=}\left[\begin{array}{ccc} 1 & 3 & 5\\ 2 & 5 & 1\\ 2 & 3 & 8\end{array}\right]\] - -then - -.. math:: - :nowrap: - - \[ \mathbf{A^{-1}=\frac{1}{25}\left[\begin{array}{ccc} -37 & 9 & 22\\ 14 & 2 & -9\\ 4 & -3 & 1\end{array}\right]=\left[\begin{array}{ccc} -1.48 & 0.36 & 0.88\\ 0.56 & 0.08 & -0.36\\ 0.16 & -0.12 & 0.04\end{array}\right].}\] - -The following example demonstrates this computation in SciPy - - >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') - >>> A - matrix([[1, 3, 5], - [2, 5, 1], - [2, 3, 8]]) - >>> A.I - matrix([[-1.48, 0.36, 0.88], - [ 0.56, 0.08, -0.36], - [ 0.16, -0.12, 0.04]]) - >>> from scipy import linalg - >>> linalg.inv(A) - array([[-1.48, 0.36, 0.88], - [ 0.56, 0.08, -0.36], - [ 0.16, -0.12, 0.04]]) - -Solving linear system -^^^^^^^^^^^^^^^^^^^^^ - -Solving linear systems of equations is straightforward using the scipy -command :obj:`linalg.solve`. This command expects an input matrix and -a right-hand-side vector. The solution vector is then computed. An -option for entering a symmetrix matrix is offered which can speed up -the processing when applicable. As an example, suppose it is desired -to solve the following simultaneous equations: - -.. math:: - :nowrap: - - \begin{eqnarray*} x+3y+5z & = & 10\\ 2x+5y+z & = & 8\\ 2x+3y+8z & = & 3\end{eqnarray*} - -We could find the solution vector using a matrix inverse: - -.. math:: - :nowrap: - - \[ \left[\begin{array}{c} x\\ y\\ z\end{array}\right]=\left[\begin{array}{ccc} 1 & 3 & 5\\ 2 & 5 & 1\\ 2 & 3 & 8\end{array}\right]^{-1}\left[\begin{array}{c} 10\\ 8\\ 3\end{array}\right]=\frac{1}{25}\left[\begin{array}{c} -232\\ 129\\ 19\end{array}\right]=\left[\begin{array}{c} -9.28\\ 5.16\\ 0.76\end{array}\right].\] - -However, it is better to use the linalg.solve command which can be -faster and more numerically stable. In this case it however gives the -same answer as shown in the following example: - - >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') - >>> b = mat('[10;8;3]') - >>> A.I*b - matrix([[-9.28], - [ 5.16], - [ 0.76]]) - >>> linalg.solve(A,b) - array([[-9.28], - [ 5.16], - [ 0.76]]) - - -Finding Determinant -^^^^^^^^^^^^^^^^^^^ - -The determinant of a square matrix :math:`\mathbf{A}` is often denoted -:math:`\left|\mathbf{A}\right|` and is a quantity often used in linear -algebra. Suppose :math:`a_{ij}` are the elements of the matrix -:math:`\mathbf{A}` and let :math:`M_{ij}=\left|\mathbf{A}_{ij}\right|` -be the determinant of the matrix left by removing the -:math:`i^{\textrm{th}}` row and :math:`j^{\textrm{th}}` column from -:math:`\mathbf{A}` . Then for any row :math:`i,` - -.. math:: - :nowrap: - - \[ \left|\mathbf{A}\right|=\sum_{j}\left(-1\right)^{i+j}a_{ij}M_{ij}.\] - -This is a recursive way to define the determinant where the base case -is defined by accepting that the determinant of a :math:`1\times1` matrix is the only matrix element. In SciPy the determinant can be -calculated with :obj:`linalg.det` . For example, the determinant of - -.. math:: - :nowrap: - - \[ \mathbf{A=}\left[\begin{array}{ccc} 1 & 3 & 5\\ 2 & 5 & 1\\ 2 & 3 & 8\end{array}\right]\] - -is - -.. math:: - :nowrap: - - \begin{eqnarray*} \left|\mathbf{A}\right| & = & 1\left|\begin{array}{cc} 5 & 1\\ 3 & 8\end{array}\right|-3\left|\begin{array}{cc} 2 & 1\\ 2 & 8\end{array}\right|+5\left|\begin{array}{cc} 2 & 5\\ 2 & 3\end{array}\right|\\ & = & 1\left(5\cdot8-3\cdot1\right)-3\left(2\cdot8-2\cdot1\right)+5\left(2\cdot3-2\cdot5\right)=-25.\end{eqnarray*} - -In SciPy this is computed as shown in this example: - - >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') - >>> linalg.det(A) - -25.000000000000004 - - -Computing norms -^^^^^^^^^^^^^^^ - -Matrix and vector norms can also be computed with SciPy. A wide range -of norm definitions are available using different parameters to the -order argument of :obj:`linalg.norm` . This function takes a rank-1 -(vectors) or a rank-2 (matrices) array and an optional order argument -(default is 2). Based on these inputs a vector or matrix norm of the -requested order is computed. - -For vector *x* , the order parameter can be any real number including -``inf`` or ``-inf``. The computed norm is - -.. math:: - :nowrap: - - \[ \left\Vert \mathbf{x}\right\Vert =\left\{ \begin{array}{cc} \max\left|x_{i}\right| & \textrm{ord}=\textrm{inf}\\ \min\left|x_{i}\right| & \textrm{ord}=-\textrm{inf}\\ \left(\sum_{i}\left|x_{i}\right|^{\textrm{ord}}\right)^{1/\textrm{ord}} & \left|\textrm{ord}\right|<\infty.\end{array}\right.\] - - - -For matrix :math:`\mathbf{A}` the only valid values for norm are :math:`\pm2,\pm1,` :math:`\pm` inf, and 'fro' (or 'f') Thus, - -.. math:: - :nowrap: - - \[ \left\Vert \mathbf{A}\right\Vert =\left\{ \begin{array}{cc} \max_{i}\sum_{j}\left|a_{ij}\right| & \textrm{ord}=\textrm{inf}\\ \min_{i}\sum_{j}\left|a_{ij}\right| & \textrm{ord}=-\textrm{inf}\\ \max_{j}\sum_{i}\left|a_{ij}\right| & \textrm{ord}=1\\ \min_{j}\sum_{i}\left|a_{ij}\right| & \textrm{ord}=-1\\ \max\sigma_{i} & \textrm{ord}=2\\ \min\sigma_{i} & \textrm{ord}=-2\\ \sqrt{\textrm{trace}\left(\mathbf{A}^{H}\mathbf{A}\right)} & \textrm{ord}=\textrm{'fro'}\end{array}\right.\] - -where :math:`\sigma_{i}` are the singular values of :math:`\mathbf{A}` . - - -Solving linear least-squares problems and pseudo-inverses -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Linear least-squares problems occur in many branches of applied -mathematics. In this problem a set of linear scaling coefficients is -sought that allow a model to fit data. In particular it is assumed -that data :math:`y_{i}` is related to data :math:`\mathbf{x}_{i}` -through a set of coefficients :math:`c_{j}` and model functions -:math:`f_{j}\left(\mathbf{x}_{i}\right)` via the model - -.. math:: - :nowrap: - - \[ y_{i}=\sum_{j}c_{j}f_{j}\left(\mathbf{x}_{i}\right)+\epsilon_{i}\] - -where :math:`\epsilon_{i}` represents uncertainty in the data. The -strategy of least squares is to pick the coefficients :math:`c_{j}` to -minimize - -.. math:: - :nowrap: - - \[ J\left(\mathbf{c}\right)=\sum_{i}\left|y_{i}-\sum_{j}c_{j}f_{j}\left(x_{i}\right)\right|^{2}.\] - - - -Theoretically, a global minimum will occur when - -.. math:: - :nowrap: - - \[ \frac{\partial J}{\partial c_{n}^{*}}=0=\sum_{i}\left(y_{i}-\sum_{j}c_{j}f_{j}\left(x_{i}\right)\right)\left(-f_{n}^{*}\left(x_{i}\right)\right)\] - -or - -.. math:: - :nowrap: - - \begin{eqnarray*} \sum_{j}c_{j}\sum_{i}f_{j}\left(x_{i}\right)f_{n}^{*}\left(x_{i}\right) & = & \sum_{i}y_{i}f_{n}^{*}\left(x_{i}\right)\\ \mathbf{A}^{H}\mathbf{Ac} & = & \mathbf{A}^{H}\mathbf{y}\end{eqnarray*} - -where - -.. math:: - :nowrap: - - \[ \left\{ \mathbf{A}\right\} _{ij}=f_{j}\left(x_{i}\right).\] - -When :math:`\mathbf{A^{H}A}` is invertible, then - -.. math:: - :nowrap: - - \[ \mathbf{c}=\left(\mathbf{A}^{H}\mathbf{A}\right)^{-1}\mathbf{A}^{H}\mathbf{y}=\mathbf{A}^{\dagger}\mathbf{y}\] - -where :math:`\mathbf{A}^{\dagger}` is called the pseudo-inverse of -:math:`\mathbf{A}.` Notice that using this definition of -:math:`\mathbf{A}` the model can be written - -.. math:: - :nowrap: - - \[ \mathbf{y}=\mathbf{Ac}+\boldsymbol{\epsilon}.\] - -The command :obj:`linalg.lstsq` will solve the linear least squares -problem for :math:`\mathbf{c}` given :math:`\mathbf{A}` and -:math:`\mathbf{y}` . In addition :obj:`linalg.pinv` or -:obj:`linalg.pinv2` (uses a different method based on singular value -decomposition) will find :math:`\mathbf{A}^{\dagger}` given -:math:`\mathbf{A}.` - -The following example and figure demonstrate the use of -:obj:`linalg.lstsq` and :obj:`linalg.pinv` for solving a data-fitting -problem. The data shown below were generated using the model: - -.. math:: - :nowrap: - - \[ y_{i}=c_{1}e^{-x_{i}}+c_{2}x_{i}\] - -where :math:`x_{i}=0.1i` for :math:`i=1\ldots10` , :math:`c_{1}=5` , -and :math:`c_{2}=4.` Noise is added to :math:`y_{i}` and the -coefficients :math:`c_{1}` and :math:`c_{2}` are estimated using -linear least squares. - -.. plot:: - - >>> from numpy import * - >>> from scipy import linalg - >>> import matplotlib.pyplot as plt - - >>> c1,c2= 5.0,2.0 - >>> i = r_[1:11] - >>> xi = 0.1*i - >>> yi = c1*exp(-xi)+c2*xi - >>> zi = yi + 0.05*max(yi)*random.randn(len(yi)) - - >>> A = c_[exp(-xi)[:,newaxis],xi[:,newaxis]] - >>> c,resid,rank,sigma = linalg.lstsq(A,zi) - - >>> xi2 = r_[0.1:1.0:100j] - >>> yi2 = c[0]*exp(-xi2) + c[1]*xi2 - - >>> plt.plot(xi,zi,'x',xi2,yi2) - >>> plt.axis([0,1.1,3.0,5.5]) - >>> plt.xlabel('$x_i$') - >>> plt.title('Data fitting with linalg.lstsq') - >>> plt.show() - -.. :caption: Example of linear least-squares fit - -Generalized inverse -^^^^^^^^^^^^^^^^^^^ - -The generalized inverse is calculated using the command -:obj:`linalg.pinv` or :obj:`linalg.pinv2`. These two commands differ -in how they compute the generalized inverse. The first uses the -linalg.lstsq algorithm while the second uses singular value -decomposition. Let :math:`\mathbf{A}` be an :math:`M\times N` matrix, -then if :math:`M>N` the generalized inverse is - -.. math:: - :nowrap: - - \[ \mathbf{A}^{\dagger}=\left(\mathbf{A}^{H}\mathbf{A}\right)^{-1}\mathbf{A}^{H}\] - -while if :math:`M>> from scipy import linalg - >>> A = mat('[1 5 2; 2 4 1; 3 6 2]') - >>> la,v = linalg.eig(A) - >>> l1,l2,l3 = la - >>> print l1, l2, l3 - (7.95791620491+0j) (-1.25766470568+0j) (0.299748500767+0j) - - >>> print v[:,0] - [-0.5297175 -0.44941741 -0.71932146] - >>> print v[:,1] - [-0.90730751 0.28662547 0.30763439] - >>> print v[:,2] - [ 0.28380519 -0.39012063 0.87593408] - >>> print sum(abs(v**2),axis=0) - [ 1. 1. 1.] - - >>> v1 = mat(v[:,0]).T - >>> print max(ravel(abs(A*v1-l1*v1))) - 8.881784197e-16 - - -Singular value decomposition -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Singular Value Decompostion (SVD) can be thought of as an extension of -the eigenvalue problem to matrices that are not square. Let -:math:`\mathbf{A}` be an :math:`M\times N` matrix with :math:`M` and -:math:`N` arbitrary. The matrices :math:`\mathbf{A}^{H}\mathbf{A}` and -:math:`\mathbf{A}\mathbf{A}^{H}` are square hermitian matrices [#]_ of -size :math:`N\times N` and :math:`M\times M` respectively. It is known -that the eigenvalues of square hermitian matrices are real and -non-negative. In addtion, there are at most -:math:`\min\left(M,N\right)` identical non-zero eigenvalues of -:math:`\mathbf{A}^{H}\mathbf{A}` and :math:`\mathbf{A}\mathbf{A}^{H}.` -Define these positive eigenvalues as :math:`\sigma_{i}^{2}.` The -square-root of these are called singular values of :math:`\mathbf{A}.` -The eigenvectors of :math:`\mathbf{A}^{H}\mathbf{A}` are collected by -columns into an :math:`N\times N` unitary [#]_ matrix -:math:`\mathbf{V}` while the eigenvectors of -:math:`\mathbf{A}\mathbf{A}^{H}` are collected by columns in the -unitary matrix :math:`\mathbf{U}` , the singular values are collected -in an :math:`M\times N` zero matrix -:math:`\mathbf{\boldsymbol{\Sigma}}` with main diagonal entries set to -the singular values. Then - -.. math:: - :nowrap: - - \[ \mathbf{A=U}\boldsymbol{\Sigma}\mathbf{V}^{H}\] - -is the singular-value decomposition of :math:`\mathbf{A}.` Every -matrix has a singular value decomposition. Sometimes, the singular -values are called the spectrum of :math:`\mathbf{A}.` The command -:obj:`linalg.svd` will return :math:`\mathbf{U}` , -:math:`\mathbf{V}^{H}` , and :math:`\sigma_{i}` as an array of the -singular values. To obtain the matrix :math:`\mathbf{\Sigma}` use -:obj:`linalg.diagsvd`. The following example illustrates the use of -:obj:`linalg.svd` . - - >>> A = mat('[1 3 2; 1 2 3]') - >>> M,N = A.shape - >>> U,s,Vh = linalg.svd(A) - >>> Sig = mat(linalg.diagsvd(s,M,N)) - >>> U, Vh = mat(U), mat(Vh) - >>> print U - [[-0.70710678 -0.70710678] - [-0.70710678 0.70710678]] - >>> print Sig - [[ 5.19615242 0. 0. ] - [ 0. 1. 0. ]] - >>> print Vh - [[ -2.72165527e-01 -6.80413817e-01 -6.80413817e-01] - [ -6.18652536e-16 -7.07106781e-01 7.07106781e-01] - [ -9.62250449e-01 1.92450090e-01 1.92450090e-01]] - - >>> print A - [[1 3 2] - [1 2 3]] - >>> print U*Sig*Vh - [[ 1. 3. 2.] - [ 1. 2. 3.]] - -.. [#] A hermitian matrix :math:`\mathbf{D}` satisfies :math:`\mathbf{D}^{H}=\mathbf{D}.` - -.. [#] A unitary matrix :math:`\mathbf{D}` satisfies :math:`\mathbf{D}^{H}\mathbf{D}=\mathbf{I}=\mathbf{D}\mathbf{D}^{H}` so that :math:`\mathbf{D}^{-1}=\mathbf{D}^{H}.` - - -LU decomposition -^^^^^^^^^^^^^^^^ - -The LU decompostion finds a representation for the :math:`M\times N` matrix :math:`\mathbf{A}` as - -.. math:: - :nowrap: - - \[ \mathbf{A}=\mathbf{PLU}\] - -where :math:`\mathbf{P}` is an :math:`M\times M` permutation matrix (a -permutation of the rows of the identity matrix), :math:`\mathbf{L}` is -in :math:`M\times K` lower triangular or trapezoidal matrix ( -:math:`K=\min\left(M,N\right)` ) with unit-diagonal, and -:math:`\mathbf{U}` is an upper triangular or trapezoidal matrix. The -SciPy command for this decomposition is :obj:`linalg.lu` . - -Such a decomposition is often useful for solving many simultaneous -equations where the left-hand-side does not change but the right hand -side does. For example, suppose we are going to solve - -.. math:: - :nowrap: - - \[ \mathbf{A}\mathbf{x}_{i}=\mathbf{b}_{i}\] - -for many different :math:`\mathbf{b}_{i}` . The LU decomposition allows this to be written as - -.. math:: - :nowrap: - - \[ \mathbf{PLUx}_{i}=\mathbf{b}_{i}.\] - -Because :math:`\mathbf{L}` is lower-triangular, the equation can be -solved for :math:`\mathbf{U}\mathbf{x}_{i}` and finally -:math:`\mathbf{x}_{i}` very rapidly using forward- and -back-substitution. An initial time spent factoring :math:`\mathbf{A}` -allows for very rapid solution of similar systems of equations in the -future. If the intent for performing LU decomposition is for solving -linear systems then the command :obj:`linalg.lu_factor` should be used -followed by repeated applications of the command -:obj:`linalg.lu_solve` to solve the system for each new -right-hand-side. - - -Cholesky decomposition -^^^^^^^^^^^^^^^^^^^^^^ - -Cholesky decomposition is a special case of LU decomposition -applicable to Hermitian positive definite matrices. When -:math:`\mathbf{A}=\mathbf{A}^{H}` and -:math:`\mathbf{x}^{H}\mathbf{Ax}\geq0` for all :math:`\mathbf{x}` , -then decompositions of :math:`\mathbf{A}` can be found so that - -.. math:: - :nowrap: - - \begin{eqnarray*} \mathbf{A} & = & \mathbf{U}^{H}\mathbf{U}\\ \mathbf{A} & = & \mathbf{L}\mathbf{L}^{H}\end{eqnarray*} - -where :math:`\mathbf{L}` is lower-triangular and :math:`\mathbf{U}` is -upper triangular. Notice that :math:`\mathbf{L}=\mathbf{U}^{H}.` The -command :obj:`linagl.cholesky` computes the cholesky -factorization. For using cholesky factorization to solve systems of -equations there are also :obj:`linalg.cho_factor` and -:obj:`linalg.cho_solve` routines that work similarly to their LU -decomposition counterparts. - - -QR decomposition -^^^^^^^^^^^^^^^^ - -The QR decomposition (sometimes called a polar decomposition) works -for any :math:`M\times N` array and finds an :math:`M\times M` unitary -matrix :math:`\mathbf{Q}` and an :math:`M\times N` upper-trapezoidal -matrix :math:`\mathbf{R}` such that - -.. math:: - :nowrap: - - \[ \mathbf{A=QR}.\] - -Notice that if the SVD of :math:`\mathbf{A}` is known then the QR decomposition can be found - -.. math:: - :nowrap: - - \[ \mathbf{A}=\mathbf{U}\boldsymbol{\Sigma}\mathbf{V}^{H}=\mathbf{QR}\] - -implies that :math:`\mathbf{Q}=\mathbf{U}` and -:math:`\mathbf{R}=\boldsymbol{\Sigma}\mathbf{V}^{H}.` Note, however, -that in SciPy independent algorithms are used to find QR and SVD -decompositions. The command for QR decomposition is :obj:`linalg.qr` . - - -Schur decomposition -^^^^^^^^^^^^^^^^^^^ - -For a square :math:`N\times N` matrix, :math:`\mathbf{A}` , the Schur -decomposition finds (not-necessarily unique) matrices -:math:`\mathbf{T}` and :math:`\mathbf{Z}` such that - -.. math:: - :nowrap: - - \[ \mathbf{A}=\mathbf{ZT}\mathbf{Z}^{H}\] - -where :math:`\mathbf{Z}` is a unitary matrix and :math:`\mathbf{T}` is -either upper-triangular or quasi-upper triangular depending on whether -or not a real schur form or complex schur form is requested. For a -real schur form both :math:`\mathbf{T}` and :math:`\mathbf{Z}` are -real-valued when :math:`\mathbf{A}` is real-valued. When -:math:`\mathbf{A}` is a real-valued matrix the real schur form is only -quasi-upper triangular because :math:`2\times2` blocks extrude from -the main diagonal corresponding to any complex- valued -eigenvalues. The command :obj:`linalg.schur` finds the Schur -decomposition while the command :obj:`linalg.rsf2csf` converts -:math:`\mathbf{T}` and :math:`\mathbf{Z}` from a real Schur form to a -complex Schur form. The Schur form is especially useful in calculating -functions of matrices. - -The following example illustrates the schur decomposition: - - >>> from scipy import linalg - >>> A = mat('[1 3 2; 1 4 5; 2 3 6]') - >>> T,Z = linalg.schur(A) - >>> T1,Z1 = linalg.schur(A,'complex') - >>> T2,Z2 = linalg.rsf2csf(T,Z) - >>> print T - [[ 9.90012467 1.78947961 -0.65498528] - [ 0. 0.54993766 -1.57754789] - [ 0. 0.51260928 0.54993766]] - >>> print T2 - [[ 9.90012467 +0.00000000e+00j -0.32436598 +1.55463542e+00j - -0.88619748 +5.69027615e-01j] - [ 0.00000000 +0.00000000e+00j 0.54993766 +8.99258408e-01j - 1.06493862 +1.37016050e-17j] - [ 0.00000000 +0.00000000e+00j 0.00000000 +0.00000000e+00j - 0.54993766 -8.99258408e-01j]] - >>> print abs(T1-T2) # different - [[ 1.24357637e-14 2.09205364e+00 6.56028192e-01] - [ 0.00000000e+00 4.00296604e-16 1.83223097e+00] - [ 0.00000000e+00 0.00000000e+00 4.57756680e-16]] - >>> print abs(Z1-Z2) # different - [[ 0.06833781 1.10591375 0.23662249] - [ 0.11857169 0.5585604 0.29617525] - [ 0.12624999 0.75656818 0.22975038]] - >>> T,Z,T1,Z1,T2,Z2 = map(mat,(T,Z,T1,Z1,T2,Z2)) - >>> print abs(A-Z*T*Z.H) # same - [[ 1.11022302e-16 4.44089210e-16 4.44089210e-16] - [ 4.44089210e-16 1.33226763e-15 8.88178420e-16] - [ 8.88178420e-16 4.44089210e-16 2.66453526e-15]] - >>> print abs(A-Z1*T1*Z1.H) # same - [[ 1.00043248e-15 2.22301403e-15 5.55749485e-15] - [ 2.88899660e-15 8.44927041e-15 9.77322008e-15] - [ 3.11291538e-15 1.15463228e-14 1.15464861e-14]] - >>> print abs(A-Z2*T2*Z2.H) # same - [[ 3.34058710e-16 8.88611201e-16 4.18773089e-18] - [ 1.48694940e-16 8.95109973e-16 8.92966151e-16] - [ 1.33228956e-15 1.33582317e-15 3.55373104e-15]] - -Matrix Functions ----------------- - -Consider the function :math:`f\left(x\right)` with Taylor series expansion - -.. math:: - :nowrap: - - \[ f\left(x\right)=\sum_{k=0}^{\infty}\frac{f^{\left(k\right)}\left(0\right)}{k!}x^{k}.\] - -A matrix function can be defined using this Taylor series for the -square matrix :math:`\mathbf{A}` as - -.. math:: - :nowrap: - - \[ f\left(\mathbf{A}\right)=\sum_{k=0}^{\infty}\frac{f^{\left(k\right)}\left(0\right)}{k!}\mathbf{A}^{k}.\] - -While, this serves as a useful representation of a matrix function, it -is rarely the best way to calculate a matrix function. - - -Exponential and logarithm functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The matrix exponential is one of the more common matrix functions. It -can be defined for square matrices as - -.. math:: - :nowrap: - - \[ e^{\mathbf{A}}=\sum_{k=0}^{\infty}\frac{1}{k!}\mathbf{A}^{k}.\] - -The command :obj:`linalg.expm3` uses this Taylor series definition to compute the matrix exponential. -Due to poor convergence properties it is not often used. - -Another method to compute the matrix exponential is to find an -eigenvalue decomposition of :math:`\mathbf{A}` : - -.. math:: - :nowrap: - - \[ \mathbf{A}=\mathbf{V}\boldsymbol{\Lambda}\mathbf{V}^{-1}\] - -and note that - -.. math:: - :nowrap: - - \[ e^{\mathbf{A}}=\mathbf{V}e^{\boldsymbol{\Lambda}}\mathbf{V}^{-1}\] - -where the matrix exponential of the diagonal matrix :math:`\boldsymbol{\Lambda}` is just the exponential of its elements. This method is implemented in :obj:`linalg.expm2` . - -The preferred method for implementing the matrix exponential is to use -scaling and a Pad? approximation for :math:`e^{x}` . This algorithm is -implemented as :obj:`linalg.expm` . - -The inverse of the matrix exponential is the matrix logarithm defined -as the inverse of the matrix exponential. - -.. math:: - :nowrap: - - \[ \mathbf{A}\equiv\exp\left(\log\left(\mathbf{A}\right)\right).\] - -The matrix logarithm can be obtained with :obj:`linalg.logm` . - - -Trigonometric functions -^^^^^^^^^^^^^^^^^^^^^^^ - -The trigonometric functions :math:`\sin` , :math:`\cos` , and -:math:`\tan` are implemented for matrices in :func:`linalg.sinm`, -:func:`linalg.cosm`, and :obj:`linalg.tanm` respectively. The matrix -sin and cosine can be defined using Euler's identity as - -.. math:: - :nowrap: - - \begin{eqnarray*} \sin\left(\mathbf{A}\right) & = & \frac{e^{j\mathbf{A}}-e^{-j\mathbf{A}}}{2j}\\ \cos\left(\mathbf{A}\right) & = & \frac{e^{j\mathbf{A}}+e^{-j\mathbf{A}}}{2}.\end{eqnarray*} - -The tangent is - -.. math:: - :nowrap: - - \[ \tan\left(x\right)=\frac{\sin\left(x\right)}{\cos\left(x\right)}=\left[\cos\left(x\right)\right]^{-1}\sin\left(x\right)\] - -and so the matrix tangent is defined as - -.. math:: - :nowrap: - - \[ \left[\cos\left(\mathbf{A}\right)\right]^{-1}\sin\left(\mathbf{A}\right).\] - - - - -Hyperbolic trigonometric functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The hyperbolic trigonemetric functions :math:`\sinh` , :math:`\cosh` , -and :math:`\tanh` can also be defined for matrices using the familiar -definitions: - -.. math:: - :nowrap: - - \begin{eqnarray*} \sinh\left(\mathbf{A}\right) & = & \frac{e^{\mathbf{A}}-e^{-\mathbf{A}}}{2}\\ \cosh\left(\mathbf{A}\right) & = & \frac{e^{\mathbf{A}}+e^{-\mathbf{A}}}{2}\\ \tanh\left(\mathbf{A}\right) & = & \left[\cosh\left(\mathbf{A}\right)\right]^{-1}\sinh\left(\mathbf{A}\right).\end{eqnarray*} - -These matrix functions can be found using :obj:`linalg.sinhm`, -:obj:`linalg.coshm` , and :obj:`linalg.tanhm`. - - -Arbitrary function -^^^^^^^^^^^^^^^^^^ - -Finally, any arbitrary function that takes one complex number and -returns a complex number can be called as a matrix function using the -command :obj:`linalg.funm`. This command takes the matrix and an -arbitrary Python function. It then implements an algorithm from Golub -and Van Loan's book "Matrix Computations "to compute function applied -to the matrix using a Schur decomposition. Note that *the function -needs to accept complex numbers* as input in order to work with this -algorithm. For example the following code computes the zeroth-order -Bessel function applied to a matrix. - - >>> from scipy import special, random, linalg - >>> A = random.rand(3,3) - >>> B = linalg.funm(A,lambda x: special.jv(0,x)) - >>> print A - [[ 0.72578091 0.34105276 0.79570345] - [ 0.65767207 0.73855618 0.541453 ] - [ 0.78397086 0.68043507 0.4837898 ]] - >>> print B - [[ 0.72599893 -0.20545711 -0.22721101] - [-0.27426769 0.77255139 -0.23422637] - [-0.27612103 -0.21754832 0.7556849 ]] - >>> print linalg.eigvals(A) - [ 1.91262611+0.j 0.21846476+0.j -0.18296399+0.j] - >>> print special.jv(0, linalg.eigvals(A)) - [ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] - >>> print linalg.eigvals(B) - [ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] - -Note how, by virtue of how matrix analytic functions are defined, -the Bessel function has acted on the matrix eigenvalues. - - -Statistics -========== - -SciPy has a tremendous number of basic statistics routines with more -easily added by the end user (if you create one please contribute it). -All of the statistics functions are located in the sub-package -:mod:`scipy.stats` and a fairly complete listing of these functions -can be had using ``info(stats)``. - - -Random Variables ----------------- - -There are two general distribution classes that have been implemented -for encapsulating continuous random variables and discrete random -variables. Over 80 continuous random variables and 10 discrete random -variables have been implemented using these classes. The list of the -random variables available is in the docstring for the stats sub- -package. A detailed description of each of them is also located in the -files continuous.lyx and discrete.lyx in the stats sub-directories. - - -.. XXX: is this up-to-date? -.. -.. Interfacing with Python Imaging Library -.. ======================================= -.. -.. If you have the Python Imaging Library installed, SciPy provides some -.. convenient functions that make use of it's facilities particularly for -.. reading, writing, displaying, and rotating images. In SciPy an image -.. is always a two- or three-dimensional array. Gray-scale, and colormap -.. images are always two-dimensional arrays while RGB images are three- -.. dimensional with the third dimension specifying the channel. -.. -.. Commands available include -.. -.. - fromimage --- convert a PIL image to a Numpy array -.. -.. - toimage --- convert Numpy array to PIL image -.. -.. - imsave --- save Numpy array to an image file -.. -.. - imread --- read an image file into a Numpy array -.. -.. - imrotate --- rotate an image (a Numpy array) counter-clockwise -.. -.. - imresize --- resize an image using the PIL -.. -.. - imshow --- external viewer of a Numpy array (using PIL) -.. -.. - imfilter --- fast, simple built-in filters provided by PIL -.. -.. - radon --- simple radon transform based on imrotate Added: trunk/doc/source/tutorial/integrate.rst =================================================================== --- trunk/doc/source/tutorial/integrate.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/integrate.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -0,0 +1,280 @@ +Integration (:mod:`scipy.integrate`) +==================================== + +.. sectionauthor:: Travis E. Oliphant + +.. currentmodule:: scipy.integrate + +The :mod:`scipy.integrate` sub-package provides several integration +techniques including an ordinary differential equation integrator. An +overview of the module is provided by the help command: + +.. literalinclude:: examples/4-1 + + +General integration (:func:`quad`) +---------------------------------- + +The function :obj:`quad` is provided to integrate a function of one +variable between two points. The points can be :math:`\pm\infty` +(:math:`\pm` ``inf``) to indicate infinite limits. For example, +suppose you wish to integrate a bessel function ``jv(2.5,x)`` along +the interval :math:`[0,4.5].` + +.. math:: + :nowrap: + + \[ I=\int_{0}^{4.5}J_{2.5}\left(x\right)\, dx.\] + +This could be computed using :obj:`quad`: + + >>> result = integrate.quad(lambda x: special.jv(2.5,x), 0, 4.5) + >>> print result + (1.1178179380783249, 7.8663172481899801e-09) + + >>> I = sqrt(2/pi)*(18.0/27*sqrt(2)*cos(4.5)-4.0/27*sqrt(2)*sin(4.5)+ + sqrt(2*pi)*special.fresnel(3/sqrt(pi))[0]) + >>> print I + 1.117817938088701 + + >>> print abs(result[0]-I) + 1.03761443881e-11 + +The first argument to quad is a "callable" Python object (*i.e* a +function, method, or class instance). Notice the use of a lambda- +function in this case as the argument. The next two arguments are the +limits of integration. The return value is a tuple, with the first +element holding the estimated value of the integral and the second +element holding an upper bound on the error. Notice, that in this +case, the true value of this integral is + +.. math:: + :nowrap: + + \[ I=\sqrt{\frac{2}{\pi}}\left(\frac{18}{27}\sqrt{2}\cos\left(4.5\right)-\frac{4}{27}\sqrt{2}\sin\left(4.5\right)+\sqrt{2\pi}\textrm{Si}\left(\frac{3}{\sqrt{\pi}}\right)\right),\] + +where + +.. math:: + :nowrap: + + \[ \textrm{Si}\left(x\right)=\int_{0}^{x}\sin\left(\frac{\pi}{2}t^{2}\right)\, dt.\] + +is the Fresnel sine integral. Note that the numerically-computed +integral is within :math:`1.04\times10^{-11}` of the exact result --- well below the reported error bound. + +Infinite inputs are also allowed in :obj:`quad` by using :math:`\pm` +``inf`` as one of the arguments. For example, suppose that a numerical +value for the exponential integral: + +.. math:: + :nowrap: + + \[ E_{n}\left(x\right)=\int_{1}^{\infty}\frac{e^{-xt}}{t^{n}}\, dt.\] + +is desired (and the fact that this integral can be computed as +``special.expn(n,x)`` is forgotten). The functionality of the function +:obj:`special.expn` can be replicated by defining a new function +:obj:`vec_expint` based on the routine :obj:`quad`: + + >>> from scipy.integrate import quad + >>> def integrand(t,n,x): + ... return exp(-x*t) / t**n + + >>> def expint(n,x): + ... return quad(integrand, 1, Inf, args=(n, x))[0] + + >>> vec_expint = vectorize(expint) + + >>> vec_expint(3,arange(1.0,4.0,0.5)) + array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049]) + >>> special.expn(3,arange(1.0,4.0,0.5)) + array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049]) + +The function which is integrated can even use the quad argument +(though the error bound may underestimate the error due to possible +numerical error in the integrand from the use of :obj:`quad` ). The integral in this case is + +.. math:: + :nowrap: + + \[ I_{n}=\int_{0}^{\infty}\int_{1}^{\infty}\frac{e^{-xt}}{t^{n}}\, dt\, dx=\frac{1}{n}.\] + +>>> result = quad(lambda x: expint(3, x), 0, inf) +>>> print result +(0.33333333324560266, 2.8548934485373678e-09) + +>>> I3 = 1.0/3.0 +>>> print I3 +0.333333333333 + +>>> print I3 - result[0] +8.77306560731e-11 + +This last example shows that multiple integration can be handled using +repeated calls to :func:`quad`. The mechanics of this for double and +triple integration have been wrapped up into the functions +:obj:`dblquad` and :obj:`tplquad`. The function, :obj:`dblquad` +performs double integration. Use the help function to be sure that the +arguments are defined in the correct order. In addition, the limits on +all inner integrals are actually functions which can be constant +functions. An example of using double integration to compute several +values of :math:`I_{n}` is shown below: + + >>> from scipy.integrate import quad, dblquad + >>> def I(n): + ... return dblquad(lambda t, x: exp(-x*t)/t**n, 0, Inf, lambda x: 1, lambda x: Inf) + + >>> print I(4) + (0.25000000000435768, 1.0518245707751597e-09) + >>> print I(3) + (0.33333333325010883, 2.8604069919261191e-09) + >>> print I(2) + (0.49999999999857514, 1.8855523253868967e-09) + + +Gaussian quadrature (integrate.gauss_quadtol) +--------------------------------------------- + +A few functions are also provided in order to perform simple Gaussian +quadrature over a fixed interval. The first is :obj:`fixed_quad` which +performs fixed-order Gaussian quadrature. The second function is +:obj:`quadrature` which performs Gaussian quadrature of multiple +orders until the difference in the integral estimate is beneath some +tolerance supplied by the user. These functions both use the module +:mod:`special.orthogonal` which can calculate the roots and quadrature +weights of a large variety of orthogonal polynomials (the polynomials +themselves are available as special functions returning instances of +the polynomial class --- e.g. :obj:`special.legendre `). + + +Integrating using samples +------------------------- + +There are three functions for computing integrals given only samples: +:obj:`trapz` , :obj:`simps`, and :obj:`romb` . The first two +functions use Newton-Coates formulas of order 1 and 2 respectively to +perform integration. These two functions can handle, +non-equally-spaced samples. The trapezoidal rule approximates the +function as a straight line between adjacent points, while Simpson's +rule approximates the function between three adjacent points as a +parabola. + +If the samples are equally-spaced and the number of samples available +is :math:`2^{k}+1` for some integer :math:`k`, then Romberg +integration can be used to obtain high-precision estimates of the +integral using the available samples. Romberg integration uses the +trapezoid rule at step-sizes related by a power of two and then +performs Richardson extrapolation on these estimates to approximate +the integral with a higher-degree of accuracy. (A different interface +to Romberg integration useful when the function can be provided is +also available as :func:`romberg`). + + +Ordinary differential equations (:func:`odeint`) +------------------------------------------------ + +Integrating a set of ordinary differential equations (ODEs) given +initial conditions is another useful example. The function +:obj:`odeint` is available in SciPy for integrating a first-order +vector differential equation: + +.. math:: + :nowrap: + + \[ \frac{d\mathbf{y}}{dt}=\mathbf{f}\left(\mathbf{y},t\right),\] + +given initial conditions :math:`\mathbf{y}\left(0\right)=y_{0}`, where +:math:`\mathbf{y}` is a length :math:`N` vector and :math:`\mathbf{f}` +is a mapping from :math:`\mathcal{R}^{N}` to :math:`\mathcal{R}^{N}.` +A higher-order ordinary differential equation can always be reduced to +a differential equation of this type by introducing intermediate +derivatives into the :math:`\mathbf{y}` vector. + +For example suppose it is desired to find the solution to the +following second-order differential equation: + +.. math:: + :nowrap: + + \[ \frac{d^{2}w}{dz^{2}}-zw(z)=0\] + +with initial conditions :math:`w\left(0\right)=\frac{1}{\sqrt[3]{3^{2}}\Gamma\left(\frac{2}{3}\right)}` and :math:`\left.\frac{dw}{dz}\right|_{z=0}=-\frac{1}{\sqrt[3]{3}\Gamma\left(\frac{1}{3}\right)}.` It is known that the solution to this differential equation with these +boundary conditions is the Airy function + +.. math:: + :nowrap: + + \[ w=\textrm{Ai}\left(z\right),\] + +which gives a means to check the integrator using :func:`special.airy `. + +First, convert this ODE into standard form by setting +:math:`\mathbf{y}=\left[\frac{dw}{dz},w\right]` and :math:`t=z`. Thus, +the differential equation becomes + +.. math:: + :nowrap: + + \[ \frac{d\mathbf{y}}{dt}=\left[\begin{array}{c} ty_{1}\\ y_{0}\end{array}\right]=\left[\begin{array}{cc} 0 & t\\ 1 & 0\end{array}\right]\left[\begin{array}{c} y_{0}\\ y_{1}\end{array}\right]=\left[\begin{array}{cc} 0 & t\\ 1 & 0\end{array}\right]\mathbf{y}.\] + +In other words, + +.. math:: + :nowrap: + + \[ \mathbf{f}\left(\mathbf{y},t\right)=\mathbf{A}\left(t\right)\mathbf{y}.\] + +As an interesting reminder, if :math:`\mathbf{A}\left(t\right)` +commutes with :math:`\int_{0}^{t}\mathbf{A}\left(\tau\right)\, d\tau` +under matrix multiplication, then this linear differential equation +has an exact solution using the matrix exponential: + +.. math:: + :nowrap: + + \[ \mathbf{y}\left(t\right)=\exp\left(\int_{0}^{t}\mathbf{A}\left(\tau\right)d\tau\right)\mathbf{y}\left(0\right),\] + +However, in this case, :math:`\mathbf{A}\left(t\right)` and its integral do not commute. + +There are many optional inputs and outputs available when using odeint +which can help tune the solver. These additional inputs and outputs +are not needed much of the time, however, and the three required input +arguments and the output solution suffice. The required inputs are the +function defining the derivative, *fprime*, the initial conditions +vector, *y0*, and the time points to obtain a solution, *t*, (with +the initial value point as the first element of this sequence). The +output to :obj:`odeint` is a matrix where each row contains the +solution vector at each requested time point (thus, the initial +conditions are given in the first output row). + +The following example illustrates the use of odeint including the +usage of the *Dfun* option which allows the user to specify a gradient +(with respect to :math:`\mathbf{y}` ) of the function, +:math:`\mathbf{f}\left(\mathbf{y},t\right)`. + + >>> from scipy.integrate import odeint + >>> from scipy.special import gamma, airy + >>> y1_0 = 1.0/3**(2.0/3.0)/gamma(2.0/3.0) + >>> y0_0 = -1.0/3**(1.0/3.0)/gamma(1.0/3.0) + >>> y0 = [y0_0, y1_0] + >>> def func(y, t): + ... return [t*y[1],y[0]] + + >>> def gradient(y,t): + ... return [[0,t],[1,0]] + + >>> x = arange(0,4.0, 0.01) + >>> t = x + >>> ychk = airy(x)[0] + >>> y = odeint(func, y0, t) + >>> y2 = odeint(func, y0, t, Dfun=gradient) + + >>> print ychk[:36:6] + [ 0.355028 0.339511 0.324068 0.308763 0.293658 0.278806] + + >>> print y[:36:6,1] + [ 0.355028 0.339511 0.324067 0.308763 0.293658 0.278806] + + >>> print y2[:36:6,1] + [ 0.355028 0.339511 0.324067 0.308763 0.293658 0.278806] Added: trunk/doc/source/tutorial/interpolate.rst =================================================================== --- trunk/doc/source/tutorial/interpolate.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/interpolate.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -0,0 +1,233 @@ +Interpolation (:mod:`scipy.interpolate`) +======================================== + +.. sectionauthor:: Travis E. Oliphant + +.. currentmodule:: scipy.interpolate + +There are two general interpolation facilities available in SciPy. The +first facility is an interpolation class which performs linear +1-dimensional interpolation. The second facility is based on the +FORTRAN library FITPACK and provides functions for 1- and +2-dimensional (smoothed) cubic-spline interpolation. + + +Linear 1-d interpolation (:class:`interp1d`) +-------------------------------------------- + +The interp1d class in scipy.interpolate is a convenient method to +create a function based on fixed data points which can be evaluated +anywhere within the domain defined by the given data using linear +interpolation. An instance of this class is created by passing the 1-d +vectors comprising the data. The instance of this class defines a +:meth:`__call__ ` method and can therefore by +treated like a function which interpolates between known data values +to obtain unknown values (it also has a docstring for help). Behavior +at the boundary can be specified at instantiation time. The following +example demonstrates it's use. + +.. plot:: + + >>> from numpy import * + >>> from scipy import interpolate + + >>> x = arange(0,10) + >>> y = exp(-x/3.0) + >>> f = interpolate.interp1d(x, y) + + >>> xnew = arange(0,9,0.1) + >>> import matplotlib.pyplot as plt + >>> plt.plot(x,y,'o',xnew,f(xnew),'-') + +.. :caption: One-dimensional interpolation using the +.. class :obj:`interpolate.interp1d` + + +Spline interpolation in 1-d (interpolate.splXXX) +------------------------------------------------ + +Spline interpolation requires two essential steps: (1) a spline +representation of the curve is computed, and (2) the spline is +evaluated at the desired points. In order to find the spline +representation, there are two different was to represent a curve and +obtain (smoothing) spline coefficients: directly and parametrically. +The direct method finds the spline representation of a curve in a two- +dimensional plane using the function :obj:`splrep`. The +first two arguments are the only ones required, and these provide the +:math:`x` and :math:`y` components of the curve. The normal output is +a 3-tuple, :math:`\left(t,c,k\right)` , containing the knot-points, +:math:`t` , the coefficients :math:`c` and the order :math:`k` of the +spline. The default spline order is cubic, but this can be changed +with the input keyword, *k.* + +For curves in :math:`N` -dimensional space the function +:obj:`splprep` allows defining the curve +parametrically. For this function only 1 input argument is +required. This input is a list of :math:`N` -arrays representing the +curve in :math:`N` -dimensional space. The length of each array is the +number of curve points, and each array provides one component of the +:math:`N` -dimensional data point. The parameter variable is given +with the keword argument, *u,* which defaults to an equally-spaced +monotonic sequence between :math:`0` and :math:`1` . The default +output consists of two objects: a 3-tuple, :math:`\left(t,c,k\right)` +, containing the spline representation and the parameter variable +:math:`u.` + +The keyword argument, *s* , is used to specify the amount of smoothing +to perform during the spline fit. The default value of :math:`s` is +:math:`s=m-\sqrt{2m}` where :math:`m` is the number of data-points +being fit. Therefore, **if no smoothing is desired a value of** +:math:`\mathbf{s}=0` **should be passed to the routines.** + +Once the spline representation of the data has been determined, +functions are available for evaluating the spline +(:func:`splev`) and its derivatives +(:func:`splev`, :func:`splade`) at any point +and the integral of the spline between any two points ( +:func:`splint`). In addition, for cubic splines ( :math:`k=3` +) with 8 or more knots, the roots of the spline can be estimated ( +:func:`sproot`). These functions are demonstrated in the +example that follows. + +.. plot:: + + >>> from numpy import * + >>> import matplotlib.pyplot as plt + >>> from scipy import interpolate + + Cubic-spline + + >>> x = arange(0,2*pi+pi/4,2*pi/8) + >>> y = sin(x) + >>> tck = interpolate.splrep(x,y,s=0) + >>> xnew = arange(0,2*pi,pi/50) + >>> ynew = interpolate.splev(xnew,tck,der=0) + + >>> plt.figure() + >>> plt.plot(x,y,'x',xnew,ynew,xnew,sin(xnew),x,y,'b') + >>> plt.legend(['Linear','Cubic Spline', 'True']) + >>> plt.axis([-0.05,6.33,-1.05,1.05]) + >>> plt.title('Cubic-spline interpolation') + >>> plt.show() + + Derivative of spline + + >>> yder = interpolate.splev(xnew,tck,der=1) + >>> plt.figure() + >>> plt.plot(xnew,yder,xnew,cos(xnew),'--') + >>> plt.legend(['Cubic Spline', 'True']) + >>> plt.axis([-0.05,6.33,-1.05,1.05]) + >>> plt.title('Derivative estimation from spline') + >>> plt.show() + + Integral of spline + + >>> def integ(x,tck,constant=-1): + >>> x = atleast_1d(x) + >>> out = zeros(x.shape, dtype=x.dtype) + >>> for n in xrange(len(out)): + >>> out[n] = interpolate.splint(0,x[n],tck) + >>> out += constant + >>> return out + >>> + >>> yint = integ(xnew,tck) + >>> plt.figure() + >>> plt.plot(xnew,yint,xnew,-cos(xnew),'--') + >>> plt.legend(['Cubic Spline', 'True']) + >>> plt.axis([-0.05,6.33,-1.05,1.05]) + >>> plt.title('Integral estimation from spline') + >>> plt.show() + + Roots of spline + + >>> print interpolate.sproot(tck) + [ 0. 3.1416] + + Parametric spline + + >>> t = arange(0,1.1,.1) + >>> x = sin(2*pi*t) + >>> y = cos(2*pi*t) + >>> tck,u = interpolate.splprep([x,y],s=0) + >>> unew = arange(0,1.01,0.01) + >>> out = interpolate.splev(unew,tck) + >>> plt.figure() + >>> plt.plot(x,y,'x',out[0],out[1],sin(2*pi*unew),cos(2*pi*unew),x,y,'b') + >>> plt.legend(['Linear','Cubic Spline', 'True']) + >>> plt.axis([-1.05,1.05,-1.05,1.05]) + >>> plt.title('Spline of parametrically-defined curve') + >>> plt.show() + + +Two-dimensional spline representation (:func:`bisplrep`) +-------------------------------------------------------- + +For (smooth) spline-fitting to a two dimensional surface, the function +:func:`bisplrep` is available. This function takes as required inputs +the **1-D** arrays *x*, *y*, and *z* which represent points on the +surface :math:`z=f\left(x,y\right).` The default output is a list +:math:`\left[tx,ty,c,kx,ky\right]` whose entries represent +respectively, the components of the knot positions, the coefficients +of the spline, and the order of the spline in each coordinate. It is +convenient to hold this list in a single object, *tck,* so that it can +be passed easily to the function :obj:`bisplev`. The +keyword, *s* , can be used to change the amount of smoothing performed +on the data while determining the appropriate spline. The default +value is :math:`s=m-\sqrt{2m}` where :math:`m` is the number of data +points in the *x, y,* and *z* vectors. As a result, if no smoothing is +desired, then :math:`s=0` should be passed to +:obj:`bisplrep` . + +To evaluate the two-dimensional spline and it's partial derivatives +(up to the order of the spline), the function +:obj:`bisplev` is required. This function takes as the +first two arguments **two 1-D arrays** whose cross-product specifies +the domain over which to evaluate the spline. The third argument is +the *tck* list returned from :obj:`bisplrep`. If desired, +the fourth and fifth arguments provide the orders of the partial +derivative in the :math:`x` and :math:`y` direction respectively. + +It is important to note that two dimensional interpolation should not +be used to find the spline representation of images. The algorithm +used is not amenable to large numbers of input points. The signal +processing toolbox contains more appropriate algorithms for finding +the spline representation of an image. The two dimensional +interpolation commands are intended for use when interpolating a two +dimensional function as shown in the example that follows. This +example uses the :obj:`mgrid ` command in SciPy which is +useful for defining a "mesh-grid "in many dimensions. (See also the +:obj:`ogrid ` command if the full-mesh is not +needed). The number of output arguments and the number of dimensions +of each argument is determined by the number of indexing objects +passed in :obj:`mgrid `[]. + +.. plot:: + + >>> from numpy import * + >>> from scipy import interpolate + >>> import matplotlib.pyplot as plt + + Define function over sparse 20x20 grid + + >>> x,y = mgrid[-1:1:20j,-1:1:20j] + >>> z = (x+y)*exp(-6.0*(x*x+y*y)) + + >>> plt.figure() + >>> plt.pcolor(x,y,z) + >>> plt.colorbar() + >>> plt.title("Sparsely sampled function.") + >>> plt.show() + + Interpolate function over new 70x70 grid + + >>> xnew,ynew = mgrid[-1:1:70j,-1:1:70j] + >>> tck = interpolate.bisplrep(x,y,z,s=0) + >>> znew = interpolate.bisplev(xnew[:,0],ynew[0,:],tck) + + >>> plt.figure() + >>> plt.pcolor(xnew,ynew,znew) + >>> plt.colorbar() + >>> plt.title("Interpolated function.") + >>> plt.show() + +.. :caption: Example of two-dimensional spline interpolation. Added: trunk/doc/source/tutorial/linalg.rst =================================================================== --- trunk/doc/source/tutorial/linalg.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/linalg.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -0,0 +1,825 @@ +Linear Algebra +============== + +.. sectionauthor:: Travis E. Oliphant + +.. currentmodule: scipy + +When SciPy is built using the optimized ATLAS LAPACK and BLAS +libraries, it has very fast linear algebra capabilities. If you dig +deep enough, all of the raw lapack and blas libraries are available +for your use for even more speed. In this section, some easier-to-use +interfaces to these routines are described. + +All of these linear algebra routines expect an object that can be +converted into a 2-dimensional array. The output of these routines is +also a two-dimensional array. There is a matrix class defined in +Numpy, which you can initialize with an appropriate Numpy array in +order to get objects for which multiplication is matrix-multiplication +instead of the default, element-by-element multiplication. + + +Matrix Class +------------ + +The matrix class is initialized with the SciPy command :obj:`mat` +which is just convenient short-hand for :class:`matrix +`. If you are going to be doing a lot of matrix-math, it +is convenient to convert arrays into matrices using this command. One +advantage of using the :func:`mat` command is that you can enter +two-dimensional matrices using MATLAB-like syntax with commas or +spaces separating columns and semicolons separting rows as long as the +matrix is placed in a string passed to :obj:`mat` . + + +Basic routines +-------------- + + +Finding Inverse +^^^^^^^^^^^^^^^ + +The inverse of a matrix :math:`\mathbf{A}` is the matrix +:math:`\mathbf{B}` such that :math:`\mathbf{AB}=\mathbf{I}` where +:math:`\mathbf{I}` is the identity matrix consisting of ones down the +main diagonal. Usually :math:`\mathbf{B}` is denoted +:math:`\mathbf{B}=\mathbf{A}^{-1}` . In SciPy, the matrix inverse of +the Numpy array, A, is obtained using :obj:`linalg.inv` ``(A)`` , or +using ``A.I`` if ``A`` is a Matrix. For example, let + +.. math:: + :nowrap: + + \[ \mathbf{A=}\left[\begin{array}{ccc} 1 & 3 & 5\\ 2 & 5 & 1\\ 2 & 3 & 8\end{array}\right]\] + +then + +.. math:: + :nowrap: + + \[ \mathbf{A^{-1}=\frac{1}{25}\left[\begin{array}{ccc} -37 & 9 & 22\\ 14 & 2 & -9\\ 4 & -3 & 1\end{array}\right]=\left[\begin{array}{ccc} -1.48 & 0.36 & 0.88\\ 0.56 & 0.08 & -0.36\\ 0.16 & -0.12 & 0.04\end{array}\right].}\] + +The following example demonstrates this computation in SciPy + + >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') + >>> A + matrix([[1, 3, 5], + [2, 5, 1], + [2, 3, 8]]) + >>> A.I + matrix([[-1.48, 0.36, 0.88], + [ 0.56, 0.08, -0.36], + [ 0.16, -0.12, 0.04]]) + >>> from scipy import linalg + >>> linalg.inv(A) + array([[-1.48, 0.36, 0.88], + [ 0.56, 0.08, -0.36], + [ 0.16, -0.12, 0.04]]) + +Solving linear system +^^^^^^^^^^^^^^^^^^^^^ + +Solving linear systems of equations is straightforward using the scipy +command :obj:`linalg.solve`. This command expects an input matrix and +a right-hand-side vector. The solution vector is then computed. An +option for entering a symmetrix matrix is offered which can speed up +the processing when applicable. As an example, suppose it is desired +to solve the following simultaneous equations: + +.. math:: + :nowrap: + + \begin{eqnarray*} x+3y+5z & = & 10\\ 2x+5y+z & = & 8\\ 2x+3y+8z & = & 3\end{eqnarray*} + +We could find the solution vector using a matrix inverse: + +.. math:: + :nowrap: + + \[ \left[\begin{array}{c} x\\ y\\ z\end{array}\right]=\left[\begin{array}{ccc} 1 & 3 & 5\\ 2 & 5 & 1\\ 2 & 3 & 8\end{array}\right]^{-1}\left[\begin{array}{c} 10\\ 8\\ 3\end{array}\right]=\frac{1}{25}\left[\begin{array}{c} -232\\ 129\\ 19\end{array}\right]=\left[\begin{array}{c} -9.28\\ 5.16\\ 0.76\end{array}\right].\] + +However, it is better to use the linalg.solve command which can be +faster and more numerically stable. In this case it however gives the +same answer as shown in the following example: + + >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') + >>> b = mat('[10;8;3]') + >>> A.I*b + matrix([[-9.28], + [ 5.16], + [ 0.76]]) + >>> linalg.solve(A,b) + array([[-9.28], + [ 5.16], + [ 0.76]]) + + +Finding Determinant +^^^^^^^^^^^^^^^^^^^ + +The determinant of a square matrix :math:`\mathbf{A}` is often denoted +:math:`\left|\mathbf{A}\right|` and is a quantity often used in linear +algebra. Suppose :math:`a_{ij}` are the elements of the matrix +:math:`\mathbf{A}` and let :math:`M_{ij}=\left|\mathbf{A}_{ij}\right|` +be the determinant of the matrix left by removing the +:math:`i^{\textrm{th}}` row and :math:`j^{\textrm{th}}` column from +:math:`\mathbf{A}` . Then for any row :math:`i,` + +.. math:: + :nowrap: + + \[ \left|\mathbf{A}\right|=\sum_{j}\left(-1\right)^{i+j}a_{ij}M_{ij}.\] + +This is a recursive way to define the determinant where the base case +is defined by accepting that the determinant of a :math:`1\times1` matrix is the only matrix element. In SciPy the determinant can be +calculated with :obj:`linalg.det` . For example, the determinant of + +.. math:: + :nowrap: + + \[ \mathbf{A=}\left[\begin{array}{ccc} 1 & 3 & 5\\ 2 & 5 & 1\\ 2 & 3 & 8\end{array}\right]\] + +is + +.. math:: + :nowrap: + + \begin{eqnarray*} \left|\mathbf{A}\right| & = & 1\left|\begin{array}{cc} 5 & 1\\ 3 & 8\end{array}\right|-3\left|\begin{array}{cc} 2 & 1\\ 2 & 8\end{array}\right|+5\left|\begin{array}{cc} 2 & 5\\ 2 & 3\end{array}\right|\\ & = & 1\left(5\cdot8-3\cdot1\right)-3\left(2\cdot8-2\cdot1\right)+5\left(2\cdot3-2\cdot5\right)=-25.\end{eqnarray*} + +In SciPy this is computed as shown in this example: + + >>> A = mat('[1 3 5; 2 5 1; 2 3 8]') + >>> linalg.det(A) + -25.000000000000004 + + +Computing norms +^^^^^^^^^^^^^^^ + +Matrix and vector norms can also be computed with SciPy. A wide range +of norm definitions are available using different parameters to the +order argument of :obj:`linalg.norm` . This function takes a rank-1 +(vectors) or a rank-2 (matrices) array and an optional order argument +(default is 2). Based on these inputs a vector or matrix norm of the +requested order is computed. + +For vector *x* , the order parameter can be any real number including +``inf`` or ``-inf``. The computed norm is + +.. math:: + :nowrap: + + \[ \left\Vert \mathbf{x}\right\Vert =\left\{ \begin{array}{cc} \max\left|x_{i}\right| & \textrm{ord}=\textrm{inf}\\ \min\left|x_{i}\right| & \textrm{ord}=-\textrm{inf}\\ \left(\sum_{i}\left|x_{i}\right|^{\textrm{ord}}\right)^{1/\textrm{ord}} & \left|\textrm{ord}\right|<\infty.\end{array}\right.\] + + + +For matrix :math:`\mathbf{A}` the only valid values for norm are :math:`\pm2,\pm1,` :math:`\pm` inf, and 'fro' (or 'f') Thus, + +.. math:: + :nowrap: + + \[ \left\Vert \mathbf{A}\right\Vert =\left\{ \begin{array}{cc} \max_{i}\sum_{j}\left|a_{ij}\right| & \textrm{ord}=\textrm{inf}\\ \min_{i}\sum_{j}\left|a_{ij}\right| & \textrm{ord}=-\textrm{inf}\\ \max_{j}\sum_{i}\left|a_{ij}\right| & \textrm{ord}=1\\ \min_{j}\sum_{i}\left|a_{ij}\right| & \textrm{ord}=-1\\ \max\sigma_{i} & \textrm{ord}=2\\ \min\sigma_{i} & \textrm{ord}=-2\\ \sqrt{\textrm{trace}\left(\mathbf{A}^{H}\mathbf{A}\right)} & \textrm{ord}=\textrm{'fro'}\end{array}\right.\] + +where :math:`\sigma_{i}` are the singular values of :math:`\mathbf{A}` . + + +Solving linear least-squares problems and pseudo-inverses +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Linear least-squares problems occur in many branches of applied +mathematics. In this problem a set of linear scaling coefficients is +sought that allow a model to fit data. In particular it is assumed +that data :math:`y_{i}` is related to data :math:`\mathbf{x}_{i}` +through a set of coefficients :math:`c_{j}` and model functions +:math:`f_{j}\left(\mathbf{x}_{i}\right)` via the model + +.. math:: + :nowrap: + + \[ y_{i}=\sum_{j}c_{j}f_{j}\left(\mathbf{x}_{i}\right)+\epsilon_{i}\] + +where :math:`\epsilon_{i}` represents uncertainty in the data. The +strategy of least squares is to pick the coefficients :math:`c_{j}` to +minimize + +.. math:: + :nowrap: + + \[ J\left(\mathbf{c}\right)=\sum_{i}\left|y_{i}-\sum_{j}c_{j}f_{j}\left(x_{i}\right)\right|^{2}.\] + + + +Theoretically, a global minimum will occur when + +.. math:: + :nowrap: + + \[ \frac{\partial J}{\partial c_{n}^{*}}=0=\sum_{i}\left(y_{i}-\sum_{j}c_{j}f_{j}\left(x_{i}\right)\right)\left(-f_{n}^{*}\left(x_{i}\right)\right)\] + +or + +.. math:: + :nowrap: + + \begin{eqnarray*} \sum_{j}c_{j}\sum_{i}f_{j}\left(x_{i}\right)f_{n}^{*}\left(x_{i}\right) & = & \sum_{i}y_{i}f_{n}^{*}\left(x_{i}\right)\\ \mathbf{A}^{H}\mathbf{Ac} & = & \mathbf{A}^{H}\mathbf{y}\end{eqnarray*} + +where + +.. math:: + :nowrap: + + \[ \left\{ \mathbf{A}\right\} _{ij}=f_{j}\left(x_{i}\right).\] + +When :math:`\mathbf{A^{H}A}` is invertible, then + +.. math:: + :nowrap: + + \[ \mathbf{c}=\left(\mathbf{A}^{H}\mathbf{A}\right)^{-1}\mathbf{A}^{H}\mathbf{y}=\mathbf{A}^{\dagger}\mathbf{y}\] + +where :math:`\mathbf{A}^{\dagger}` is called the pseudo-inverse of +:math:`\mathbf{A}.` Notice that using this definition of +:math:`\mathbf{A}` the model can be written + +.. math:: + :nowrap: + + \[ \mathbf{y}=\mathbf{Ac}+\boldsymbol{\epsilon}.\] + +The command :obj:`linalg.lstsq` will solve the linear least squares +problem for :math:`\mathbf{c}` given :math:`\mathbf{A}` and +:math:`\mathbf{y}` . In addition :obj:`linalg.pinv` or +:obj:`linalg.pinv2` (uses a different method based on singular value +decomposition) will find :math:`\mathbf{A}^{\dagger}` given +:math:`\mathbf{A}.` + +The following example and figure demonstrate the use of +:obj:`linalg.lstsq` and :obj:`linalg.pinv` for solving a data-fitting +problem. The data shown below were generated using the model: + +.. math:: + :nowrap: + + \[ y_{i}=c_{1}e^{-x_{i}}+c_{2}x_{i}\] + +where :math:`x_{i}=0.1i` for :math:`i=1\ldots10` , :math:`c_{1}=5` , +and :math:`c_{2}=4.` Noise is added to :math:`y_{i}` and the +coefficients :math:`c_{1}` and :math:`c_{2}` are estimated using +linear least squares. + +.. plot:: + + >>> from numpy import * + >>> from scipy import linalg + >>> import matplotlib.pyplot as plt + + >>> c1,c2= 5.0,2.0 + >>> i = r_[1:11] + >>> xi = 0.1*i + >>> yi = c1*exp(-xi)+c2*xi + >>> zi = yi + 0.05*max(yi)*random.randn(len(yi)) + + >>> A = c_[exp(-xi)[:,newaxis],xi[:,newaxis]] + >>> c,resid,rank,sigma = linalg.lstsq(A,zi) + + >>> xi2 = r_[0.1:1.0:100j] + >>> yi2 = c[0]*exp(-xi2) + c[1]*xi2 + + >>> plt.plot(xi,zi,'x',xi2,yi2) + >>> plt.axis([0,1.1,3.0,5.5]) + >>> plt.xlabel('$x_i$') + >>> plt.title('Data fitting with linalg.lstsq') + >>> plt.show() + +.. :caption: Example of linear least-squares fit + +Generalized inverse +^^^^^^^^^^^^^^^^^^^ + +The generalized inverse is calculated using the command +:obj:`linalg.pinv` or :obj:`linalg.pinv2`. These two commands differ +in how they compute the generalized inverse. The first uses the +linalg.lstsq algorithm while the second uses singular value +decomposition. Let :math:`\mathbf{A}` be an :math:`M\times N` matrix, +then if :math:`M>N` the generalized inverse is + +.. math:: + :nowrap: + + \[ \mathbf{A}^{\dagger}=\left(\mathbf{A}^{H}\mathbf{A}\right)^{-1}\mathbf{A}^{H}\] + +while if :math:`M>> from scipy import linalg + >>> A = mat('[1 5 2; 2 4 1; 3 6 2]') + >>> la,v = linalg.eig(A) + >>> l1,l2,l3 = la + >>> print l1, l2, l3 + (7.95791620491+0j) (-1.25766470568+0j) (0.299748500767+0j) + + >>> print v[:,0] + [-0.5297175 -0.44941741 -0.71932146] + >>> print v[:,1] + [-0.90730751 0.28662547 0.30763439] + >>> print v[:,2] + [ 0.28380519 -0.39012063 0.87593408] + >>> print sum(abs(v**2),axis=0) + [ 1. 1. 1.] + + >>> v1 = mat(v[:,0]).T + >>> print max(ravel(abs(A*v1-l1*v1))) + 8.881784197e-16 + + +Singular value decomposition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Singular Value Decompostion (SVD) can be thought of as an extension of +the eigenvalue problem to matrices that are not square. Let +:math:`\mathbf{A}` be an :math:`M\times N` matrix with :math:`M` and +:math:`N` arbitrary. The matrices :math:`\mathbf{A}^{H}\mathbf{A}` and +:math:`\mathbf{A}\mathbf{A}^{H}` are square hermitian matrices [#]_ of +size :math:`N\times N` and :math:`M\times M` respectively. It is known +that the eigenvalues of square hermitian matrices are real and +non-negative. In addtion, there are at most +:math:`\min\left(M,N\right)` identical non-zero eigenvalues of +:math:`\mathbf{A}^{H}\mathbf{A}` and :math:`\mathbf{A}\mathbf{A}^{H}.` +Define these positive eigenvalues as :math:`\sigma_{i}^{2}.` The +square-root of these are called singular values of :math:`\mathbf{A}.` +The eigenvectors of :math:`\mathbf{A}^{H}\mathbf{A}` are collected by +columns into an :math:`N\times N` unitary [#]_ matrix +:math:`\mathbf{V}` while the eigenvectors of +:math:`\mathbf{A}\mathbf{A}^{H}` are collected by columns in the +unitary matrix :math:`\mathbf{U}` , the singular values are collected +in an :math:`M\times N` zero matrix +:math:`\mathbf{\boldsymbol{\Sigma}}` with main diagonal entries set to +the singular values. Then + +.. math:: + :nowrap: + + \[ \mathbf{A=U}\boldsymbol{\Sigma}\mathbf{V}^{H}\] + +is the singular-value decomposition of :math:`\mathbf{A}.` Every +matrix has a singular value decomposition. Sometimes, the singular +values are called the spectrum of :math:`\mathbf{A}.` The command +:obj:`linalg.svd` will return :math:`\mathbf{U}` , +:math:`\mathbf{V}^{H}` , and :math:`\sigma_{i}` as an array of the +singular values. To obtain the matrix :math:`\mathbf{\Sigma}` use +:obj:`linalg.diagsvd`. The following example illustrates the use of +:obj:`linalg.svd` . + + >>> A = mat('[1 3 2; 1 2 3]') + >>> M,N = A.shape + >>> U,s,Vh = linalg.svd(A) + >>> Sig = mat(linalg.diagsvd(s,M,N)) + >>> U, Vh = mat(U), mat(Vh) + >>> print U + [[-0.70710678 -0.70710678] + [-0.70710678 0.70710678]] + >>> print Sig + [[ 5.19615242 0. 0. ] + [ 0. 1. 0. ]] + >>> print Vh + [[ -2.72165527e-01 -6.80413817e-01 -6.80413817e-01] + [ -6.18652536e-16 -7.07106781e-01 7.07106781e-01] + [ -9.62250449e-01 1.92450090e-01 1.92450090e-01]] + + >>> print A + [[1 3 2] + [1 2 3]] + >>> print U*Sig*Vh + [[ 1. 3. 2.] + [ 1. 2. 3.]] + +.. [#] A hermitian matrix :math:`\mathbf{D}` satisfies :math:`\mathbf{D}^{H}=\mathbf{D}.` + +.. [#] A unitary matrix :math:`\mathbf{D}` satisfies :math:`\mathbf{D}^{H}\mathbf{D}=\mathbf{I}=\mathbf{D}\mathbf{D}^{H}` so that :math:`\mathbf{D}^{-1}=\mathbf{D}^{H}.` + + +LU decomposition +^^^^^^^^^^^^^^^^ + +The LU decompostion finds a representation for the :math:`M\times N` matrix :math:`\mathbf{A}` as + +.. math:: + :nowrap: + + \[ \mathbf{A}=\mathbf{PLU}\] + +where :math:`\mathbf{P}` is an :math:`M\times M` permutation matrix (a +permutation of the rows of the identity matrix), :math:`\mathbf{L}` is +in :math:`M\times K` lower triangular or trapezoidal matrix ( +:math:`K=\min\left(M,N\right)` ) with unit-diagonal, and +:math:`\mathbf{U}` is an upper triangular or trapezoidal matrix. The +SciPy command for this decomposition is :obj:`linalg.lu` . + +Such a decomposition is often useful for solving many simultaneous +equations where the left-hand-side does not change but the right hand +side does. For example, suppose we are going to solve + +.. math:: + :nowrap: + + \[ \mathbf{A}\mathbf{x}_{i}=\mathbf{b}_{i}\] + +for many different :math:`\mathbf{b}_{i}` . The LU decomposition allows this to be written as + +.. math:: + :nowrap: + + \[ \mathbf{PLUx}_{i}=\mathbf{b}_{i}.\] + +Because :math:`\mathbf{L}` is lower-triangular, the equation can be +solved for :math:`\mathbf{U}\mathbf{x}_{i}` and finally +:math:`\mathbf{x}_{i}` very rapidly using forward- and +back-substitution. An initial time spent factoring :math:`\mathbf{A}` +allows for very rapid solution of similar systems of equations in the +future. If the intent for performing LU decomposition is for solving +linear systems then the command :obj:`linalg.lu_factor` should be used +followed by repeated applications of the command +:obj:`linalg.lu_solve` to solve the system for each new +right-hand-side. + + +Cholesky decomposition +^^^^^^^^^^^^^^^^^^^^^^ + +Cholesky decomposition is a special case of LU decomposition +applicable to Hermitian positive definite matrices. When +:math:`\mathbf{A}=\mathbf{A}^{H}` and +:math:`\mathbf{x}^{H}\mathbf{Ax}\geq0` for all :math:`\mathbf{x}` , +then decompositions of :math:`\mathbf{A}` can be found so that + +.. math:: + :nowrap: + + \begin{eqnarray*} \mathbf{A} & = & \mathbf{U}^{H}\mathbf{U}\\ \mathbf{A} & = & \mathbf{L}\mathbf{L}^{H}\end{eqnarray*} + +where :math:`\mathbf{L}` is lower-triangular and :math:`\mathbf{U}` is +upper triangular. Notice that :math:`\mathbf{L}=\mathbf{U}^{H}.` The +command :obj:`linagl.cholesky` computes the cholesky +factorization. For using cholesky factorization to solve systems of +equations there are also :obj:`linalg.cho_factor` and +:obj:`linalg.cho_solve` routines that work similarly to their LU +decomposition counterparts. + + +QR decomposition +^^^^^^^^^^^^^^^^ + +The QR decomposition (sometimes called a polar decomposition) works +for any :math:`M\times N` array and finds an :math:`M\times M` unitary +matrix :math:`\mathbf{Q}` and an :math:`M\times N` upper-trapezoidal +matrix :math:`\mathbf{R}` such that + +.. math:: + :nowrap: + + \[ \mathbf{A=QR}.\] + +Notice that if the SVD of :math:`\mathbf{A}` is known then the QR decomposition can be found + +.. math:: + :nowrap: + + \[ \mathbf{A}=\mathbf{U}\boldsymbol{\Sigma}\mathbf{V}^{H}=\mathbf{QR}\] + +implies that :math:`\mathbf{Q}=\mathbf{U}` and +:math:`\mathbf{R}=\boldsymbol{\Sigma}\mathbf{V}^{H}.` Note, however, +that in SciPy independent algorithms are used to find QR and SVD +decompositions. The command for QR decomposition is :obj:`linalg.qr` . + + +Schur decomposition +^^^^^^^^^^^^^^^^^^^ + +For a square :math:`N\times N` matrix, :math:`\mathbf{A}` , the Schur +decomposition finds (not-necessarily unique) matrices +:math:`\mathbf{T}` and :math:`\mathbf{Z}` such that + +.. math:: + :nowrap: + + \[ \mathbf{A}=\mathbf{ZT}\mathbf{Z}^{H}\] + +where :math:`\mathbf{Z}` is a unitary matrix and :math:`\mathbf{T}` is +either upper-triangular or quasi-upper triangular depending on whether +or not a real schur form or complex schur form is requested. For a +real schur form both :math:`\mathbf{T}` and :math:`\mathbf{Z}` are +real-valued when :math:`\mathbf{A}` is real-valued. When +:math:`\mathbf{A}` is a real-valued matrix the real schur form is only +quasi-upper triangular because :math:`2\times2` blocks extrude from +the main diagonal corresponding to any complex- valued +eigenvalues. The command :obj:`linalg.schur` finds the Schur +decomposition while the command :obj:`linalg.rsf2csf` converts +:math:`\mathbf{T}` and :math:`\mathbf{Z}` from a real Schur form to a +complex Schur form. The Schur form is especially useful in calculating +functions of matrices. + +The following example illustrates the schur decomposition: + + >>> from scipy import linalg + >>> A = mat('[1 3 2; 1 4 5; 2 3 6]') + >>> T,Z = linalg.schur(A) + >>> T1,Z1 = linalg.schur(A,'complex') + >>> T2,Z2 = linalg.rsf2csf(T,Z) + >>> print T + [[ 9.90012467 1.78947961 -0.65498528] + [ 0. 0.54993766 -1.57754789] + [ 0. 0.51260928 0.54993766]] + >>> print T2 + [[ 9.90012467 +0.00000000e+00j -0.32436598 +1.55463542e+00j + -0.88619748 +5.69027615e-01j] + [ 0.00000000 +0.00000000e+00j 0.54993766 +8.99258408e-01j + 1.06493862 +1.37016050e-17j] + [ 0.00000000 +0.00000000e+00j 0.00000000 +0.00000000e+00j + 0.54993766 -8.99258408e-01j]] + >>> print abs(T1-T2) # different + [[ 1.24357637e-14 2.09205364e+00 6.56028192e-01] + [ 0.00000000e+00 4.00296604e-16 1.83223097e+00] + [ 0.00000000e+00 0.00000000e+00 4.57756680e-16]] + >>> print abs(Z1-Z2) # different + [[ 0.06833781 1.10591375 0.23662249] + [ 0.11857169 0.5585604 0.29617525] + [ 0.12624999 0.75656818 0.22975038]] + >>> T,Z,T1,Z1,T2,Z2 = map(mat,(T,Z,T1,Z1,T2,Z2)) + >>> print abs(A-Z*T*Z.H) # same + [[ 1.11022302e-16 4.44089210e-16 4.44089210e-16] + [ 4.44089210e-16 1.33226763e-15 8.88178420e-16] + [ 8.88178420e-16 4.44089210e-16 2.66453526e-15]] + >>> print abs(A-Z1*T1*Z1.H) # same + [[ 1.00043248e-15 2.22301403e-15 5.55749485e-15] + [ 2.88899660e-15 8.44927041e-15 9.77322008e-15] + [ 3.11291538e-15 1.15463228e-14 1.15464861e-14]] + >>> print abs(A-Z2*T2*Z2.H) # same + [[ 3.34058710e-16 8.88611201e-16 4.18773089e-18] + [ 1.48694940e-16 8.95109973e-16 8.92966151e-16] + [ 1.33228956e-15 1.33582317e-15 3.55373104e-15]] + +Matrix Functions +---------------- + +Consider the function :math:`f\left(x\right)` with Taylor series expansion + +.. math:: + :nowrap: + + \[ f\left(x\right)=\sum_{k=0}^{\infty}\frac{f^{\left(k\right)}\left(0\right)}{k!}x^{k}.\] + +A matrix function can be defined using this Taylor series for the +square matrix :math:`\mathbf{A}` as + +.. math:: + :nowrap: + + \[ f\left(\mathbf{A}\right)=\sum_{k=0}^{\infty}\frac{f^{\left(k\right)}\left(0\right)}{k!}\mathbf{A}^{k}.\] + +While, this serves as a useful representation of a matrix function, it +is rarely the best way to calculate a matrix function. + + +Exponential and logarithm functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The matrix exponential is one of the more common matrix functions. It +can be defined for square matrices as + +.. math:: + :nowrap: + + \[ e^{\mathbf{A}}=\sum_{k=0}^{\infty}\frac{1}{k!}\mathbf{A}^{k}.\] + +The command :obj:`linalg.expm3` uses this Taylor series definition to compute the matrix exponential. +Due to poor convergence properties it is not often used. + +Another method to compute the matrix exponential is to find an +eigenvalue decomposition of :math:`\mathbf{A}` : + +.. math:: + :nowrap: + + \[ \mathbf{A}=\mathbf{V}\boldsymbol{\Lambda}\mathbf{V}^{-1}\] + +and note that + +.. math:: + :nowrap: + + \[ e^{\mathbf{A}}=\mathbf{V}e^{\boldsymbol{\Lambda}}\mathbf{V}^{-1}\] + +where the matrix exponential of the diagonal matrix :math:`\boldsymbol{\Lambda}` is just the exponential of its elements. This method is implemented in :obj:`linalg.expm2` . + +The preferred method for implementing the matrix exponential is to use +scaling and a Pad? approximation for :math:`e^{x}` . This algorithm is +implemented as :obj:`linalg.expm` . + +The inverse of the matrix exponential is the matrix logarithm defined +as the inverse of the matrix exponential. + +.. math:: + :nowrap: + + \[ \mathbf{A}\equiv\exp\left(\log\left(\mathbf{A}\right)\right).\] + +The matrix logarithm can be obtained with :obj:`linalg.logm` . + + +Trigonometric functions +^^^^^^^^^^^^^^^^^^^^^^^ + +The trigonometric functions :math:`\sin` , :math:`\cos` , and +:math:`\tan` are implemented for matrices in :func:`linalg.sinm`, +:func:`linalg.cosm`, and :obj:`linalg.tanm` respectively. The matrix +sin and cosine can be defined using Euler's identity as + +.. math:: + :nowrap: + + \begin{eqnarray*} \sin\left(\mathbf{A}\right) & = & \frac{e^{j\mathbf{A}}-e^{-j\mathbf{A}}}{2j}\\ \cos\left(\mathbf{A}\right) & = & \frac{e^{j\mathbf{A}}+e^{-j\mathbf{A}}}{2}.\end{eqnarray*} + +The tangent is + +.. math:: + :nowrap: + + \[ \tan\left(x\right)=\frac{\sin\left(x\right)}{\cos\left(x\right)}=\left[\cos\left(x\right)\right]^{-1}\sin\left(x\right)\] + +and so the matrix tangent is defined as + +.. math:: + :nowrap: + + \[ \left[\cos\left(\mathbf{A}\right)\right]^{-1}\sin\left(\mathbf{A}\right).\] + + + + +Hyperbolic trigonometric functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The hyperbolic trigonemetric functions :math:`\sinh` , :math:`\cosh` , +and :math:`\tanh` can also be defined for matrices using the familiar +definitions: + +.. math:: + :nowrap: + + \begin{eqnarray*} \sinh\left(\mathbf{A}\right) & = & \frac{e^{\mathbf{A}}-e^{-\mathbf{A}}}{2}\\ \cosh\left(\mathbf{A}\right) & = & \frac{e^{\mathbf{A}}+e^{-\mathbf{A}}}{2}\\ \tanh\left(\mathbf{A}\right) & = & \left[\cosh\left(\mathbf{A}\right)\right]^{-1}\sinh\left(\mathbf{A}\right).\end{eqnarray*} + +These matrix functions can be found using :obj:`linalg.sinhm`, +:obj:`linalg.coshm` , and :obj:`linalg.tanhm`. + + +Arbitrary function +^^^^^^^^^^^^^^^^^^ + +Finally, any arbitrary function that takes one complex number and +returns a complex number can be called as a matrix function using the +command :obj:`linalg.funm`. This command takes the matrix and an +arbitrary Python function. It then implements an algorithm from Golub +and Van Loan's book "Matrix Computations "to compute function applied +to the matrix using a Schur decomposition. Note that *the function +needs to accept complex numbers* as input in order to work with this +algorithm. For example the following code computes the zeroth-order +Bessel function applied to a matrix. + + >>> from scipy import special, random, linalg + >>> A = random.rand(3,3) + >>> B = linalg.funm(A,lambda x: special.jv(0,x)) + >>> print A + [[ 0.72578091 0.34105276 0.79570345] + [ 0.65767207 0.73855618 0.541453 ] + [ 0.78397086 0.68043507 0.4837898 ]] + >>> print B + [[ 0.72599893 -0.20545711 -0.22721101] + [-0.27426769 0.77255139 -0.23422637] + [-0.27612103 -0.21754832 0.7556849 ]] + >>> print linalg.eigvals(A) + [ 1.91262611+0.j 0.21846476+0.j -0.18296399+0.j] + >>> print special.jv(0, linalg.eigvals(A)) + [ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] + >>> print linalg.eigvals(B) + [ 0.27448286+0.j 0.98810383+0.j 0.99164854+0.j] + +Note how, by virtue of how matrix analytic functions are defined, +the Bessel function has acted on the matrix eigenvalues. + Added: trunk/doc/source/tutorial/optimize.rst =================================================================== --- trunk/doc/source/tutorial/optimize.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/optimize.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -0,0 +1,464 @@ +Optimization (optimize) +======================= + +.. sectionauthor:: Travis E. Oliphant + +.. currentmodule:: scipy.optimize + +There are several classical optimization algorithms provided by SciPy +in the :mod:`scipy.optimize` package. An overview of the module is +available using :func:`help` (or :func:`pydoc.help`): + +.. literalinclude:: examples/5-1 + +The first four algorithms are unconstrained minimization algorithms +(:func:`fmin`: Nelder-Mead simplex, :func:`fmin_bfgs`: BFGS, +:func:`fmin_ncg`: Newton Conjugate Gradient, and :func:`leastsq`: +Levenburg-Marquardt). The last algorithm actually finds the roots of a +general function of possibly many variables. It is included in the +optimization package because at the (non-boundary) extreme points of a +function, the gradient is equal to zero. + + +Nelder-Mead Simplex algorithm (:func:`fmin`) +-------------------------------------------- + +The simplex algorithm is probably the simplest way to minimize a +fairly well-behaved function. The simplex algorithm requires only +function evaluations and is a good choice for simple minimization +problems. However, because it does not use any gradient evaluations, +it may take longer to find the minimum. To demonstrate the +minimization function consider the problem of minimizing the +Rosenbrock function of :math:`N` variables: + +.. math:: + :nowrap: + + \[ f\left(\mathbf{x}\right)=\sum_{i=1}^{N-1}100\left(x_{i}-x_{i-1}^{2}\right)^{2}+\left(1-x_{i-1}\right)^{2}.\] + +The minimum value of this function is 0 which is achieved when :math:`x_{i}=1.` This minimum can be found using the :obj:`fmin` routine as shown in the example below: + + >>> from scipy.optimize import fmin + >>> def rosen(x): + ... """The Rosenbrock function""" + ... return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0) + + >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] + >>> xopt = fmin(rosen, x0, xtol=1e-8) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 339 + Function evaluations: 571 + + >>> print xopt + [ 1. 1. 1. 1. 1.] + +Another optimization algorithm that needs only function calls to find +the minimum is Powell's method available as :func:`fmin_powell`. + + +Broyden-Fletcher-Goldfarb-Shanno algorithm (:func:`fmin_bfgs`) +-------------------------------------------------------------- + +In order to converge more quickly to the solution, this routine uses +the gradient of the objective function. If the gradient is not given +by the user, then it is estimated using first-differences. The +Broyden-Fletcher-Goldfarb-Shanno (BFGS) method typically requires +fewer function calls than the simplex algorithm even when the gradient +must be estimated. + +To demonstrate this algorithm, the Rosenbrock function is again used. +The gradient of the Rosenbrock function is the vector: + +.. math:: + :nowrap: + + \begin{eqnarray*} \frac{\partial f}{\partial x_{j}} & = & \sum_{i=1}^{N}200\left(x_{i}-x_{i-1}^{2}\right)\left(\delta_{i,j}-2x_{i-1}\delta_{i-1,j}\right)-2\left(1-x_{i-1}\right)\delta_{i-1,j}.\\ & = & 200\left(x_{j}-x_{j-1}^{2}\right)-400x_{j}\left(x_{j+1}-x_{j}^{2}\right)-2\left(1-x_{j}\right).\end{eqnarray*} + +This expression is valid for the interior derivatives. Special cases +are + +.. math:: + :nowrap: + + \begin{eqnarray*} \frac{\partial f}{\partial x_{0}} & = & -400x_{0}\left(x_{1}-x_{0}^{2}\right)-2\left(1-x_{0}\right),\\ \frac{\partial f}{\partial x_{N-1}} & = & 200\left(x_{N-1}-x_{N-2}^{2}\right).\end{eqnarray*} + +A Python function which computes this gradient is constructed by the +code-segment: + + >>> def rosen_der(x): + ... xm = x[1:-1] + ... xm_m1 = x[:-2] + ... xm_p1 = x[2:] + ... der = zeros_like(x) + ... der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm) + ... der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0]) + ... der[-1] = 200*(x[-1]-x[-2]**2) + ... return der + +The calling signature for the BFGS minimization algorithm is similar +to :obj:`fmin` with the addition of the *fprime* argument. An example +usage of :obj:`fmin_bfgs` is shown in the following example which +minimizes the Rosenbrock function. + + >>> from scipy.optimize import fmin_bfgs + + >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] + >>> xopt = fmin_bfgs(rosen, x0, fprime=rosen_der) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 53 + Function evaluations: 65 + Gradient evaluations: 65 + >>> print xopt + [ 1. 1. 1. 1. 1.] + + +Newton-Conjugate-Gradient (:func:`fmin_ncg`) +-------------------------------------------- + +The method which requires the fewest function calls and is therefore +often the fastest method to minimize functions of many variables is +:obj:`fmin_ncg`. This method is a modified Newton's method and uses a +conjugate gradient algorithm to (approximately) invert the local +Hessian. Newton's method is based on fitting the function locally to +a quadratic form: + +.. math:: + :nowrap: + + \[ f\left(\mathbf{x}\right)\approx f\left(\mathbf{x}_{0}\right)+\nabla f\left(\mathbf{x}_{0}\right)\cdot\left(\mathbf{x}-\mathbf{x}_{0}\right)+\frac{1}{2}\left(\mathbf{x}-\mathbf{x}_{0}\right)^{T}\mathbf{H}\left(\mathbf{x}_{0}\right)\left(\mathbf{x}-\mathbf{x}_{0}\right).\] + +where :math:`\mathbf{H}\left(\mathbf{x}_{0}\right)` is a matrix of second-derivatives (the Hessian). If the Hessian is +positive definite then the local minimum of this function can be found +by setting the gradient of the quadratic form to zero, resulting in + +.. math:: + :nowrap: + + \[ \mathbf{x}_{\textrm{opt}}=\mathbf{x}_{0}-\mathbf{H}^{-1}\nabla f.\] + +The inverse of the Hessian is evaluted using the conjugate-gradient +method. An example of employing this method to minimizing the +Rosenbrock function is given below. To take full advantage of the +NewtonCG method, a function which computes the Hessian must be +provided. The Hessian matrix itself does not need to be constructed, +only a vector which is the product of the Hessian with an arbitrary +vector needs to be available to the minimization routine. As a result, +the user can provide either a function to compute the Hessian matrix, +or a function to compute the product of the Hessian with an arbitrary +vector. + + +Full Hessian example: +^^^^^^^^^^^^^^^^^^^^^ + +The Hessian of the Rosenbrock function is + +.. math:: + :nowrap: + + \begin{eqnarray*} H_{ij}=\frac{\partial^{2}f}{\partial x_{i}\partial x_{j}} & = & 200\left(\delta_{i,j}-2x_{i-1}\delta_{i-1,j}\right)-400x_{i}\left(\delta_{i+1,j}-2x_{i}\delta_{i,j}\right)-400\delta_{i,j}\left(x_{i+1}-x_{i}^{2}\right)+2\delta_{i,j},\\ & = & \left(202+1200x_{i}^{2}-400x_{i+1}\right)\delta_{i,j}-400x_{i}\delta_{i+1,j}-400x_{i-1}\delta_{i-1,j},\end{eqnarray*} + +if :math:`i,j\in\left[1,N-2\right]` with :math:`i,j\in\left[0,N-1\right]` defining the :math:`N\times N` matrix. Other non-zero entries of the matrix are + +.. math:: + :nowrap: + + \begin{eqnarray*} \frac{\partial^{2}f}{\partial x_{0}^{2}} & = & 1200x_{0}^{2}-400x_{1}+2,\\ \frac{\partial^{2}f}{\partial x_{0}\partial x_{1}}=\frac{\partial^{2}f}{\partial x_{1}\partial x_{0}} & = & -400x_{0},\\ \frac{\partial^{2}f}{\partial x_{N-1}\partial x_{N-2}}=\frac{\partial^{2}f}{\partial x_{N-2}\partial x_{N-1}} & = & -400x_{N-2},\\ \frac{\partial^{2}f}{\partial x_{N-1}^{2}} & = & 200.\end{eqnarray*} + +For example, the Hessian when :math:`N=5` is + +.. math:: + :nowrap: + + \[ \mathbf{H}=\left[\begin{array}{ccccc} 1200x_{0}^{2}-400x_{1}+2 & -400x_{0} & 0 & 0 & 0\\ -400x_{0} & 202+1200x_{1}^{2}-400x_{2} & -400x_{1} & 0 & 0\\ 0 & -400x_{1} & 202+1200x_{2}^{2}-400x_{3} & -400x_{2} & 0\\ 0 & & -400x_{2} & 202+1200x_{3}^{2}-400x_{4} & -400x_{3}\\ 0 & 0 & 0 & -400x_{3} & 200\end{array}\right].\] + +The code which computes this Hessian along with the code to minimize +the function using :obj:`fmin_ncg` is shown in the following example: + + >>> from scipy.optimize import fmin_ncg + >>> def rosen_hess(x): + ... x = asarray(x) + ... H = diag(-400*x[:-1],1) - diag(400*x[:-1],-1) + ... diagonal = zeros_like(x) + ... diagonal[0] = 1200*x[0]-400*x[1]+2 + ... diagonal[-1] = 200 + ... diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:] + ... H = H + diag(diagonal) + ... return H + + >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] + >>> xopt = fmin_ncg(rosen, x0, rosen_der, fhess=rosen_hess, avextol=1e-8) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 23 + Function evaluations: 26 + Gradient evaluations: 23 + Hessian evaluations: 23 + >>> print xopt + [ 1. 1. 1. 1. 1.] + + +Hessian product example: +^^^^^^^^^^^^^^^^^^^^^^^^ + +For larger minimization problems, storing the entire Hessian matrix +can consume considerable time and memory. The Newton-CG algorithm only +needs the product of the Hessian times an arbitrary vector. As a +result, the user can supply code to compute this product rather than +the full Hessian by setting the *fhess_p* keyword to the desired +function. The *fhess_p* function should take the minimization vector as +the first argument and the arbitrary vector as the second +argument. Any extra arguments passed to the function to be minimized +will also be passed to this function. If possible, using Newton-CG +with the hessian product option is probably the fastest way to +minimize the function. + +In this case, the product of the Rosenbrock Hessian with an arbitrary +vector is not difficult to compute. If :math:`\mathbf{p}` is the arbitrary vector, then :math:`\mathbf{H}\left(\mathbf{x}\right)\mathbf{p}` has elements: + +.. math:: + :nowrap: + + \[ \mathbf{H}\left(\mathbf{x}\right)\mathbf{p}=\left[\begin{array}{c} \left(1200x_{0}^{2}-400x_{1}+2\right)p_{0}-400x_{0}p_{1}\\ \vdots\\ -400x_{i-1}p_{i-1}+\left(202+1200x_{i}^{2}-400x_{i+1}\right)p_{i}-400x_{i}p_{i+1}\\ \vdots\\ -400x_{N-2}p_{N-2}+200p_{N-1}\end{array}\right].\] + +Code which makes use of the *fhess_p* keyword to minimize the +Rosenbrock function using :obj:`fmin_ncg` follows: + + >>> from scipy.optimize import fmin_ncg + >>> def rosen_hess_p(x,p): + ... x = asarray(x) + ... Hp = zeros_like(x) + ... Hp[0] = (1200*x[0]**2 - 400*x[1] + 2)*p[0] - 400*x[0]*p[1] + ... Hp[1:-1] = -400*x[:-2]*p[:-2]+(202+1200*x[1:-1]**2-400*x[2:])*p[1:-1] \ + ... -400*x[1:-1]*p[2:] + ... Hp[-1] = -400*x[-2]*p[-2] + 200*p[-1] + ... return Hp + + >>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2] + >>> xopt = fmin_ncg(rosen, x0, rosen_der, fhess_p=rosen_hess_p, avextol=1e-8) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 22 + Function evaluations: 25 + Gradient evaluations: 22 + Hessian evaluations: 54 + >>> print xopt + [ 1. 1. 1. 1. 1.] + + +Least-square fitting (:func:`leastsq`) +-------------------------------------- + +All of the previously-explained minimization procedures can be used to +solve a least-squares problem provided the appropriate objective +function is constructed. For example, suppose it is desired to fit a +set of data :math:`\left\{\mathbf{x}_{i}, \mathbf{y}_{i}\right\}` +to a known model, +:math:`\mathbf{y}=\mathbf{f}\left(\mathbf{x},\mathbf{p}\right)` +where :math:`\mathbf{p}` is a vector of parameters for the model that +need to be found. A common method for determining which parameter +vector gives the best fit to the data is to minimize the sum of squares +of the residuals. The residual is usually defined for each observed +data-point as + +.. math:: + :nowrap: + + \[ e_{i}\left(\mathbf{p},\mathbf{y}_{i},\mathbf{x}_{i}\right)=\left\Vert \mathbf{y}_{i}-\mathbf{f}\left(\mathbf{x}_{i},\mathbf{p}\right)\right\Vert .\] + +An objective function to pass to any of the previous minization +algorithms to obtain a least-squares fit is. + +.. math:: + :nowrap: + + \[ J\left(\mathbf{p}\right)=\sum_{i=0}^{N-1}e_{i}^{2}\left(\mathbf{p}\right).\] + + + +The :obj:`leastsq` algorithm performs this squaring and summing of the +residuals automatically. It takes as an input argument the vector +function :math:`\mathbf{e}\left(\mathbf{p}\right)` and returns the +value of :math:`\mathbf{p}` which minimizes +:math:`J\left(\mathbf{p}\right)=\mathbf{e}^{T}\mathbf{e}` +directly. The user is also encouraged to provide the Jacobian matrix +of the function (with derivatives down the columns or across the +rows). If the Jacobian is not provided, it is estimated. + +An example should clarify the usage. Suppose it is believed some +measured data follow a sinusoidal pattern + +.. math:: + :nowrap: + + \[ y_{i}=A\sin\left(2\pi kx_{i}+\theta\right)\] + +where the parameters :math:`A,` :math:`k` , and :math:`\theta` are unknown. The residual vector is + +.. math:: + :nowrap: + + \[ e_{i}=\left|y_{i}-A\sin\left(2\pi kx_{i}+\theta\right)\right|.\] + +By defining a function to compute the residuals and (selecting an +appropriate starting position), the least-squares fit routine can be +used to find the best-fit parameters :math:`\hat{A},\,\hat{k},\,\hat{\theta}`. +This is shown in the following example: + +.. plot:: + + >>> from numpy import * + >>> x = arange(0,6e-2,6e-2/30) + >>> A,k,theta = 10, 1.0/3e-2, pi/6 + >>> y_true = A*sin(2*pi*k*x+theta) + >>> y_meas = y_true + 2*random.randn(len(x)) + + >>> def residuals(p, y, x): + ... A,k,theta = p + ... err = y-A*sin(2*pi*k*x+theta) + ... return err + + >>> def peval(x, p): + ... return p[0]*sin(2*pi*p[1]*x+p[2]) + + >>> p0 = [8, 1/2.3e-2, pi/3] + >>> print array(p0) + [ 8. 43.4783 1.0472] + + >>> from scipy.optimize import leastsq + >>> plsq = leastsq(residuals, p0, args=(y_meas, x)) + >>> print plsq[0] + [ 10.9437 33.3605 0.5834] + + >>> print array([A, k, theta]) + [ 10. 33.3333 0.5236] + + >>> import matplotlib.pyplot as plt + >>> plt.plot(x,peval(x,plsq[0]),x,y_meas,'o',x,y_true) + >>> plt.title('Least-squares fit to noisy data') + >>> plt.legend(['Fit', 'Noisy', 'True']) + >>> plt.show() + +.. :caption: Least-square fitting to noisy data using +.. :obj:`scipy.optimize.leastsq` + + +Scalar function minimizers +-------------------------- + +Often only the minimum of a scalar function is needed (a scalar +function is one that takes a scalar as input and returns a scalar +output). In these circumstances, other optimization techniques have +been developed that can work faster. + + +Unconstrained minimization (:func:`brent`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are actually two methods that can be used to minimize a scalar +function (:obj:`brent` and :func:`golden`), but :obj:`golden` is +included only for academic purposes and should rarely be used. The +brent method uses Brent's algorithm for locating a minimum. Optimally +a bracket should be given which contains the minimum desired. A +bracket is a triple :math:`\left(a,b,c\right)` such that +:math:`f\left(a\right)>f\left(b\right)>> from scipy.special import j1 + >>> from scipy.optimize import fminbound + >>> xmin = fminbound(j1, 4, 7) + >>> print xmin + 5.33144184241 + + +Root finding +------------ + + +Sets of equations +^^^^^^^^^^^^^^^^^ + +To find the roots of a polynomial, the command :obj:`roots +` is useful. To find a root of a set of non-linear +equations, the command :obj:`fsolve` is needed. For example, the +following example finds the roots of the single-variable +transcendental equation + +.. math:: + :nowrap: + + \[ x+2\cos\left(x\right)=0,\] + +and the set of non-linear equations + +.. math:: + :nowrap: + + \begin{eqnarray*} x_{0}\cos\left(x_{1}\right) & = & 4,\\ x_{0}x_{1}-x_{1} & = & 5.\end{eqnarray*} + +The results are :math:`x=-1.0299` and :math:`x_{0}=6.5041,\, x_{1}=0.9084` . + + >>> def func(x): + ... return x + 2*cos(x) + + >>> def func2(x): + ... out = [x[0]*cos(x[1]) - 4] + ... out.append(x[1]*x[0] - x[1] - 5) + ... return out + + >>> from scipy.optimize import fsolve + >>> x0 = fsolve(func, 0.3) + >>> print x0 + -1.02986652932 + + >>> x02 = fsolve(func2, [1, 1]) + >>> print x02 + [ 6.50409711 0.90841421] + + + +Scalar function root finding +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If one has a single-variable equation, there are four different root +finder algorithms that can be tried. Each of these root finding +algorithms requires the endpoints of an interval where a root is +suspected (because the function changes signs). In general +:obj:`brentq` is the best choice, but the other methods may be useful +in certain circumstances or for academic purposes. + + +Fixed-point solving +^^^^^^^^^^^^^^^^^^^ + +A problem closely related to finding the zeros of a function is the +problem of finding a fixed-point of a function. A fixed point of a +function is the point at which evaluation of the function returns the +point: :math:`g\left(x\right)=x.` Clearly the fixed point of :math:`g` +is the root of :math:`f\left(x\right)=g\left(x\right)-x.` +Equivalently, the root of :math:`f` is the fixed_point of +:math:`g\left(x\right)=f\left(x\right)+x.` The routine +:obj:`fixed_point` provides a simple iterative method using Aitkens +sequence acceleration to estimate the fixed point of :math:`g` given a +starting point. + Added: trunk/doc/source/tutorial/signal.rst =================================================================== --- trunk/doc/source/tutorial/signal.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/signal.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -0,0 +1,544 @@ +Signal Processing (signal) +========================== + +.. sectionauthor:: Travis E. Oliphant + +The signal processing toolbox currently contains some filtering +functions, a limited set of filter design tools, and a few B-spline +interpolation algorithms for one- and two-dimensional data. While the +B-spline algorithms could technically be placed under the +interpolation category, they are included here because they only work +with equally-spaced data and make heavy use of filter-theory and +transfer-function formalism to provide a fast B-spline transform. To +understand this section you will need to understand that a signal in +SciPy is an array of real or complex numbers. + + +B-splines +--------- + +A B-spline is an approximation of a continuous function over a finite- +domain in terms of B-spline coefficients and knot points. If the knot- +points are equally spaced with spacing :math:`\Delta x` , then the B-spline approximation to a 1-dimensional function is the +finite-basis expansion. + +.. math:: + :nowrap: + + \[ y\left(x\right)\approx\sum_{j}c_{j}\beta^{o}\left(\frac{x}{\Delta x}-j\right).\] + +In two dimensions with knot-spacing :math:`\Delta x` and :math:`\Delta y` , the function representation is + +.. math:: + :nowrap: + + \[ z\left(x,y\right)\approx\sum_{j}\sum_{k}c_{jk}\beta^{o}\left(\frac{x}{\Delta x}-j\right)\beta^{o}\left(\frac{y}{\Delta y}-k\right).\] + +In these expressions, :math:`\beta^{o}\left(\cdot\right)` is the space-limited B-spline basis function of order, :math:`o` . The requirement of equally-spaced knot-points and equally-spaced +data points, allows the development of fast (inverse-filtering) +algorithms for determining the coefficients, :math:`c_{j}` , from sample-values, :math:`y_{n}` . Unlike the general spline interpolation algorithms, these algorithms +can quickly find the spline coefficients for large images. + +The advantage of representing a set of samples via B-spline basis +functions is that continuous-domain operators (derivatives, re- +sampling, integral, etc.) which assume that the data samples are drawn +from an underlying continuous function can be computed with relative +ease from the spline coefficients. For example, the second-derivative +of a spline is + +.. math:: + :nowrap: + + \[ y{}^{\prime\prime}\left(x\right)=\frac{1}{\Delta x^{2}}\sum_{j}c_{j}\beta^{o\prime\prime}\left(\frac{x}{\Delta x}-j\right).\] + +Using the property of B-splines that + +.. math:: + :nowrap: + + \[ \frac{d^{2}\beta^{o}\left(w\right)}{dw^{2}}=\beta^{o-2}\left(w+1\right)-2\beta^{o-2}\left(w\right)+\beta^{o-2}\left(w-1\right)\] + +it can be seen that + +.. math:: + :nowrap: + + \[ y^{\prime\prime}\left(x\right)=\frac{1}{\Delta x^{2}}\sum_{j}c_{j}\left[\beta^{o-2}\left(\frac{x}{\Delta x}-j+1\right)-2\beta^{o-2}\left(\frac{x}{\Delta x}-j\right)+\beta^{o-2}\left(\frac{x}{\Delta x}-j-1\right)\right].\] + +If :math:`o=3` , then at the sample points, + +.. math:: + :nowrap: + + \begin{eqnarray*} \Delta x^{2}\left.y^{\prime}\left(x\right)\right|_{x=n\Delta x} & = & \sum_{j}c_{j}\delta_{n-j+1}-2c_{j}\delta_{n-j}+c_{j}\delta_{n-j-1},\\ & = & c_{n+1}-2c_{n}+c_{n-1}.\end{eqnarray*} + +Thus, the second-derivative signal can be easily calculated from the +spline fit. if desired, smoothing splines can be found to make the +second-derivative less sensitive to random-errors. + +The savvy reader will have already noticed that the data samples are +related to the knot coefficients via a convolution operator, so that +simple convolution with the sampled B-spline function recovers the +original data from the spline coefficients. The output of convolutions +can change depending on how boundaries are handled (this becomes +increasingly more important as the number of dimensions in the data- +set increases). The algorithms relating to B-splines in the signal- +processing sub package assume mirror-symmetric boundary conditions. +Thus, spline coefficients are computed based on that assumption, and +data-samples can be recovered exactly from the spline coefficients by +assuming them to be mirror-symmetric also. + +Currently the package provides functions for determining second- and +third-order cubic spline coefficients from equally spaced samples in +one- and two-dimensions (:func:`signal.qspline1d`, +:func:`signal.qspline2d`, :func:`signal.cspline1d`, +:func:`signal.cspline2d`). The package also supplies a function ( +:obj:`signal.bspline` ) for evaluating the bspline basis function, +:math:`\beta^{o}\left(x\right)` for arbitrary order and :math:`x.` For +large :math:`o` , the B-spline basis function can be approximated well +by a zero-mean Gaussian function with standard-deviation equal to +:math:`\sigma_{o}=\left(o+1\right)/12` : + +.. math:: + :nowrap: + + \[ \beta^{o}\left(x\right)\approx\frac{1}{\sqrt{2\pi\sigma_{o}^{2}}}\exp\left(-\frac{x^{2}}{2\sigma_{o}}\right).\] + +A function to compute this Gaussian for arbitrary :math:`x` and +:math:`o` is also available ( :obj:`signal.gauss_spline` ). The +following code and Figure uses spline-filtering to compute an +edge-image (the second-derivative of a smoothed spline) of Lena's face +which is an array returned by the command :func:`lena`. The command +:obj:`signal.sepfir2d` was used to apply a separable two-dimensional +FIR filter with mirror- symmetric boundary conditions to the spline +coefficients. This function is ideally suited for reconstructing +samples from spline coefficients and is faster than +:obj:`signal.convolve2d` which convolves arbitrary two-dimensional +filters and allows for choosing mirror-symmetric boundary conditions. + +.. plot:: + + >>> from numpy import * + >>> from scipy import signal, misc + >>> import matplotlib.pyplot as plt + + >>> image = misc.lena().astype(float32) + >>> derfilt = array([1.0,-2,1.0],float32) + >>> ck = signal.cspline2d(image,8.0) + >>> deriv = signal.sepfir2d(ck, derfilt, [1]) + \ + >>> signal.sepfir2d(ck, [1], derfilt) + + Alternatively we could have done:: + + laplacian = array([[0,1,0],[1,-4,1],[0,1,0]],float32) + deriv2 = signal.convolve2d(ck,laplacian,mode='same',boundary='symm') + + >>> plt.figure() + >>> plt.imshow(image) + >>> plt.gray() + >>> plt.title('Original image') + >>> plt.show() + + >>> plt.figure() + >>> plt.imshow(deriv) + >>> plt.gray() + >>> plt.title('Output of spline edge filter') + >>> plt.show() + +.. :caption: Example of using smoothing splines to filter images. + + +Filtering +--------- + +Filtering is a generic name for any system that modifies an input +signal in some way. In SciPy a signal can be thought of as a Numpy +array. There are different kinds of filters for different kinds of +operations. There are two broad kinds of filtering operations: linear +and non-linear. Linear filters can always be reduced to multiplication +of the flattened Numpy array by an appropriate matrix resulting in +another flattened Numpy array. Of course, this is not usually the best +way to compute the filter as the matrices and vectors involved may be +huge. For example filtering a :math:`512\times512` image with this +method would require multiplication of a :math:`512^{2}x512^{2}` +matrix with a :math:`512^{2}` vector. Just trying to store the +:math:`512^{2}\times512^{2}` matrix using a standard Numpy array would +require :math:`68,719,476,736` elements. At 4 bytes per element this +would require :math:`256\textrm{GB}` of memory. In most applications +most of the elements of this matrix are zero and a different method +for computing the output of the filter is employed. + + +Convolution/Correlation +^^^^^^^^^^^^^^^^^^^^^^^ + +Many linear filters also have the property of shift-invariance. This +means that the filtering operation is the same at different locations +in the signal and it implies that the filtering matrix can be +constructed from knowledge of one row (or column) of the matrix alone. +In this case, the matrix multiplication can be accomplished using +Fourier transforms. + +Let :math:`x\left[n\right]` define a one-dimensional signal indexed by the integer :math:`n.` Full convolution of two one-dimensional signals can be expressed as + +.. math:: + :nowrap: + + \[ y\left[n\right]=\sum_{k=-\infty}^{\infty}x\left[k\right]h\left[n-k\right].\] + +This equation can only be implemented directly if we limit the +sequences to finite support sequences that can be stored in a +computer, choose :math:`n=0` to be the starting point of both +sequences, let :math:`K+1` be that value for which +:math:`y\left[n\right]=0` for all :math:`n>K+1` and :math:`M+1` be +that value for which :math:`x\left[n\right]=0` for all :math:`n>M+1` , +then the discrete convolution expression is + +.. math:: + :nowrap: + + \[ y\left[n\right]=\sum_{k=\max\left(n-M,0\right)}^{\min\left(n,K\right)}x\left[k\right]h\left[n-k\right].\] + +For convenience assume :math:`K\geq M.` Then, more explicitly the output of this operation is + +.. math:: + :nowrap: + + \begin{eqnarray*} y\left[0\right] & = & x\left[0\right]h\left[0\right]\\ y\left[1\right] & = & x\left[0\right]h\left[1\right]+x\left[1\right]h\left[0\right]\\ y\left[2\right] & = & x\left[0\right]h\left[2\right]+x\left[1\right]h\left[1\right]+x\left[2\right]h\left[0\right]\\ \vdots & \vdots & \vdots\\ y\left[M\right] & = & x\left[0\right]h\left[M\right]+x\left[1\right]h\left[M-1\right]+\cdots+x\left[M\right]h\left[0\right]\\ y\left[M+1\right] & = & x\left[1\right]h\left[M\right]+x\left[2\right]h\left[M-1\right]+\cdots+x\left[M+1\right]h\left[0\right]\\ \vdots & \vdots & \vdots\\ y\left[K\right] & = & x\left[K-M\right]h\left[M\right]+\cdots+x\left[K\right]h\left[0\right]\\ y\left[K+1\right] & = & x\left[K+1-M\right]h\left[M\right]+\cdots+x\left[K\right]h\left[1\right]\\ \vdots & \vdots & \vdots\\ y\left[K+M-1\right] & = & x\left[K-1\right]h\left[M\right]+x\left[K\right]h\left[M-1\right]\\ y\left[K+M\right] & = & x\left[K\right]h\left[M\right].\end{eqnarray*} + +Thus, the full discrete convolution of two finite sequences of lengths :math:`K+1` and :math:`M+1` respectively results in a finite sequence of length :math:`K+M+1=\left(K+1\right)+\left(M+1\right)-1.` + +One dimensional convolution is implemented in SciPy with the function +``signal.convolve`` . This function takes as inputs the signals +:math:`x,` :math:`h` , and an optional flag and returns the signal +:math:`y.` The optional flag allows for specification of which part of +the output signal to return. The default value of 'full' returns the +entire signal. If the flag has a value of 'same' then only the middle +:math:`K` values are returned starting at :math:`y\left[\left\lfloor +\frac{M-1}{2}\right\rfloor \right]` so that the output has the same +length as the largest input. If the flag has a value of 'valid' then +only the middle :math:`K-M+1=\left(K+1\right)-\left(M+1\right)+1` +output values are returned where :math:`z` depends on all of the +values of the smallest input from :math:`h\left[0\right]` to +:math:`h\left[M\right].` In other words only the values +:math:`y\left[M\right]` to :math:`y\left[K\right]` inclusive are +returned. + +This same function ``signal.convolve`` can actually take :math:`N` +-dimensional arrays as inputs and will return the :math:`N` +-dimensional convolution of the two arrays. The same input flags are +available for that case as well. + +Correlation is very similar to convolution except for the minus sign +becomes a plus sign. Thus + +.. math:: + :nowrap: + + \[ w\left[n\right]=\sum_{k=-\infty}^{\infty}y\left[k\right]x\left[n+k\right]\] + +is the (cross) correlation of the signals :math:`y` and :math:`x.` For finite-length signals with :math:`y\left[n\right]=0` outside of the range :math:`\left[0,K\right]` and :math:`x\left[n\right]=0` outside of the range :math:`\left[0,M\right],` the summation can simplify to + +.. math:: + :nowrap: + + \[ w\left[n\right]=\sum_{k=\max\left(0,-n\right)}^{\min\left(K,M-n\right)}y\left[k\right]x\left[n+k\right].\] + +Assuming again that :math:`K\geq M` this is + +.. math:: + :nowrap: + + \begin{eqnarray*} w\left[-K\right] & = & y\left[K\right]x\left[0\right]\\ w\left[-K+1\right] & = & y\left[K-1\right]x\left[0\right]+y\left[K\right]x\left[1\right]\\ \vdots & \vdots & \vdots\\ w\left[M-K\right] & = & y\left[K-M\right]x\left[0\right]+y\left[K-M+1\right]x\left[1\right]+\cdots+y\left[K\right]x\left[M\right]\\ w\left[M-K+1\right] & = & y\left[K-M-1\right]x\left[0\right]+\cdots+y\left[K-1\right]x\left[M\right]\\ \vdots & \vdots & \vdots\\ w\left[-1\right] & = & y\left[1\right]x\left[0\right]+y\left[2\right]x\left[1\right]+\cdots+y\left[M+1\right]x\left[M\right]\\ w\left[0\right] & = & y\left[0\right]x\left[0\right]+y\left[1\right]x\left[1\right]+\cdots+y\left[M\right]x\left[M\right]\\ w\left[1\right] & = & y\left[0\right]x\left[1\right]+y\left[1\right]x\left[2\right]+\cdots+y\left[M-1\right]x\left[M\right]\\ w\left[2\right] & = & y\left[0\right]x\left[2\right]+y\left[1\right]x\left[3\right]+\cdots+y\left[M-2\right]x\left[M\right]\\ \vdots & \vdots & \vdots\\ w\left[M-1\right] & = & y\left[0\right]x\left[M-1\right]+y\left[1\right]x\left[M\right]\\ w\left[M\right] & = & y\left[0\right]x\left[M\right].\end{eqnarray*} + + + +The SciPy function ``signal.correlate`` implements this +operation. Equivalent flags are available for this operation to return +the full :math:`K+M+1` length sequence ('full') or a sequence with the +same size as the largest sequence starting at +:math:`w\left[-K+\left\lfloor \frac{M-1}{2}\right\rfloor \right]` +('same') or a sequence where the values depend on all the values of +the smallest sequence ('valid'). This final option returns the +:math:`K-M+1` values :math:`w\left[M-K\right]` to +:math:`w\left[0\right]` inclusive. + +The function :obj:`signal.correlate` can also take arbitrary :math:`N` +-dimensional arrays as input and return the :math:`N` -dimensional +convolution of the two arrays on output. + +When :math:`N=2,` :obj:`signal.correlate` and/or +:obj:`signal.convolve` can be used to construct arbitrary image +filters to perform actions such as blurring, enhancing, and +edge-detection for an image. + +Convolution is mainly used for filtering when one of the signals is +much smaller than the other ( :math:`K\gg M` ), otherwise linear +filtering is more easily accomplished in the frequency domain (see +Fourier Transforms). + + +Difference-equation filtering +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A general class of linear one-dimensional filters (that includes +convolution filters) are filters described by the difference equation + +.. math:: + :nowrap: + + \[ \sum_{k=0}^{N}a_{k}y\left[n-k\right]=\sum_{k=0}^{M}b_{k}x\left[n-k\right]\] + +where :math:`x\left[n\right]` is the input sequence and +:math:`y\left[n\right]` is the output sequence. If we assume initial +rest so that :math:`y\left[n\right]=0` for :math:`n<0` , then this +kind of filter can be implemented using convolution. However, the +convolution filter sequence :math:`h\left[n\right]` could be infinite +if :math:`a_{k}\neq0` for :math:`k\geq1.` In addition, this general +class of linear filter allows initial conditions to be placed on +:math:`y\left[n\right]` for :math:`n<0` resulting in a filter that +cannot be expressed using convolution. + +The difference equation filter can be thought of as finding :math:`y\left[n\right]` recursively in terms of it's previous values + +.. math:: + :nowrap: + + \[ a_{0}y\left[n\right]=-a_{1}y\left[n-1\right]-\cdots-a_{N}y\left[n-N\right]+\cdots+b_{0}x\left[n\right]+\cdots+b_{M}x\left[n-M\right].\] + +Often :math:`a_{0}=1` is chosen for normalization. The implementation +in SciPy of this general difference equation filter is a little more +complicated then would be implied by the previous equation. It is +implemented so that only one signal needs to be delayed. The actual +implementation equations are (assuming :math:`a_{0}=1` ). + +.. math:: + :nowrap: + + \begin{eqnarray*} y\left[n\right] & = & b_{0}x\left[n\right]+z_{0}\left[n-1\right]\\ z_{0}\left[n\right] & = & b_{1}x\left[n\right]+z_{1}\left[n-1\right]-a_{1}y\left[n\right]\\ z_{1}\left[n\right] & = & b_{2}x\left[n\right]+z_{2}\left[n-1\right]-a_{2}y\left[n\right]\\ \vdots & \vdots & \vdots\\ z_{K-2}\left[n\right] & = & b_{K-1}x\left[n\right]+z_{K-1}\left[n-1\right]-a_{K-1}y\left[n\right]\\ z_{K-1}\left[n\right] & = & b_{K}x\left[n\right]-a_{K}y\left[n\right],\end{eqnarray*} + +where :math:`K=\max\left(N,M\right).` Note that :math:`b_{K}=0` if +:math:`K>M` and :math:`a_{K}=0` if :math:`K>N.` In this way, the +output at time :math:`n` depends only on the input at time :math:`n` +and the value of :math:`z_{0}` at the previous time. This can always +be calculated as long as the :math:`K` values +:math:`z_{0}\left[n-1\right]\ldots z_{K-1}\left[n-1\right]` are +computed and stored at each time step. + +The difference-equation filter is called using the command +:obj:`signal.lfilter` in SciPy. This command takes as inputs the +vector :math:`b,` the vector, :math:`a,` a signal :math:`x` and +returns the vector :math:`y` (the same length as :math:`x` ) computed +using the equation given above. If :math:`x` is :math:`N` +-dimensional, then the filter is computed along the axis provided. If, +desired, initial conditions providing the values of +:math:`z_{0}\left[-1\right]` to :math:`z_{K-1}\left[-1\right]` can be +provided or else it will be assumed that they are all zero. If initial +conditions are provided, then the final conditions on the intermediate +variables are also returned. These could be used, for example, to +restart the calculation in the same state. + +Sometimes it is more convenient to express the initial conditions in +terms of the signals :math:`x\left[n\right]` and +:math:`y\left[n\right].` In other words, perhaps you have the values +of :math:`x\left[-M\right]` to :math:`x\left[-1\right]` and the values +of :math:`y\left[-N\right]` to :math:`y\left[-1\right]` and would like +to determine what values of :math:`z_{m}\left[-1\right]` should be +delivered as initial conditions to the difference-equation filter. It +is not difficult to show that for :math:`0\leq m>> help(special).`` Each function also has it's own +documentation accessible using help. If you don't see a function you +need, consider writing it and contributing it to the library. You can +write the function in either C, Fortran, or Python. Look in the source +code of the library for examples of each of these kind of functions. Added: trunk/doc/source/tutorial/stats.rst =================================================================== --- trunk/doc/source/tutorial/stats.rst 2008-12-07 22:05:26 UTC (rev 5233) +++ trunk/doc/source/tutorial/stats.rst 2008-12-07 22:05:52 UTC (rev 5234) @@ -0,0 +1,22 @@ +Statistics +========== + +.. sectionauthor:: Travis E. Oliphant + +SciPy has a tremendous number of basic statistics routines with more +easily added by the end user (if you create one please contribute it). +All of the statistics functions are located in the sub-package +:mod:`scipy.stats` and a fairly complete listing of these functions +can be had using ``info(stats)``. + + +Random Variables +---------------- + +There are two general distribution classes that have been implemented +for encapsulating continuous random variables and discrete random +variables. Over 80 continuous random variables and 10 discrete random +variables have been implemented using these classes. The list of the +random variables available is in the docstring for the stats sub- +package. A detailed description of each of them is also located in the +files continuous.lyx and discrete.lyx in the stats sub-directories. From scipy-svn at scipy.org Sun Dec 7 17:06:55 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 7 Dec 2008 16:06:55 -0600 (CST) Subject: [Scipy-svn] r5235 - in trunk/doc: . frontpage/_templates source Message-ID: <20081207220655.7869CC7C00E@scipy.org> Author: ptvirtan Date: 2008-12-07 16:06:29 -0600 (Sun, 07 Dec 2008) New Revision: 5235 Modified: trunk/doc/Makefile trunk/doc/frontpage/_templates/indexcontent.html trunk/doc/source/conf.py Log: docs: tune document names Modified: trunk/doc/Makefile =================================================================== --- trunk/doc/Makefile 2008-12-07 22:05:52 UTC (rev 5234) +++ trunk/doc/Makefile 2008-12-07 22:06:29 UTC (rev 5235) @@ -38,11 +38,12 @@ -make -C build/latex all-pdf -test -d build/htmlhelp || make htmlhelp-build -rm -rf build/dist - cp -r build/html build/dist + mkdir -p build/dist + cp -r build/html build/dist/reference touch build/dist/index.html - perl -pi -e 's#^\s*(
  • SciPy.*?Manual.*?»
  • )\s*$$#
  • Numpy and Scipy Documentation »
  • $$1#;' build/dist/*.html build/dist/*/*.html build/dist/*/*/*.html + perl -pi -e 's#^\s*(
  • SciPy.*?Reference Guide.*?»
  • )\s*$$#
  • Numpy and Scipy Documentation »
  • $$1#;' build/dist/*.html build/dist/*/*.html build/dist/*/*/*.html (cd build/html && zip -9qr ../dist/scipy-html.zip .) - cp build/latex/scipy.pdf build/dist + cp build/latex/scipy*.pdf build/dist -cp build/htmlhelp/scipy.chm build/dist cd build/dist && tar czf ../dist.tar.gz * chmod ug=rwX,o=rX -R build/dist Modified: trunk/doc/frontpage/_templates/indexcontent.html =================================================================== --- trunk/doc/frontpage/_templates/indexcontent.html 2008-12-07 22:05:52 UTC (rev 5234) +++ trunk/doc/frontpage/_templates/indexcontent.html 2008-12-07 22:06:29 UTC (rev 5235) @@ -24,7 +24,8 @@ [PDF]

    Modified: trunk/doc/source/conf.py =================================================================== --- trunk/doc/source/conf.py 2008-12-07 22:05:52 UTC (rev 5234) +++ trunk/doc/source/conf.py 2008-12-07 22:06:29 UTC (rev 5235) @@ -86,7 +86,7 @@ # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = "%s v%s Manual (DRAFT)" % (project, version) +html_title = "%s v%s Reference Guide (DRAFT)" % (project, version) # The name of an image file (within the static path) to place at the top of # the sidebar. @@ -152,7 +152,7 @@ # (source start file, target name, title, author, document class [howto/manual]). _stdauthor = 'Written by the SciPy community' latex_documents = [ - ('index', 'scipy.tex', 'SciPy Guide', _stdauthor, 'manual'), + ('index', 'scipy-ref.tex', 'SciPy Reference Guide', _stdauthor, 'manual'), # ('user/index', 'scipy-user.tex', 'SciPy User Guide', # _stdauthor, 'manual'), ] From scipy-svn at scipy.org Sun Dec 7 19:08:31 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 7 Dec 2008 18:08:31 -0600 (CST) Subject: [Scipy-svn] r5236 - in trunk: doc/source scipy/cluster/tests scipy/interpolate/tests scipy/io/matlab/tests scipy/linalg scipy/signal scipy/sparse/linalg/eigen/arpack scipy/stats scipy/stats/tests Message-ID: <20081208000831.B6A6EC7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-07 18:08:23 -0600 (Sun, 07 Dec 2008) New Revision: 5236 Modified: trunk/doc/source/conf.py trunk/scipy/cluster/tests/test_hierarchy.py trunk/scipy/interpolate/tests/test_fitpack.py trunk/scipy/io/matlab/tests/test_mio.py trunk/scipy/linalg/decomp.py trunk/scipy/signal/signaltools.py trunk/scipy/sparse/linalg/eigen/arpack/setup.py trunk/scipy/stats/distributions.py trunk/scipy/stats/stats.py trunk/scipy/stats/tests/test_discrete_basic.py trunk/scipy/stats/tests/test_stats.py Log: ran reindent Modified: trunk/doc/source/conf.py =================================================================== --- trunk/doc/source/conf.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/doc/source/conf.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -239,4 +239,3 @@ """ plot_output_dir = '_static/plot_directive' plot_include_source = True - Modified: trunk/scipy/cluster/tests/test_hierarchy.py =================================================================== --- trunk/scipy/cluster/tests/test_hierarchy.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/cluster/tests/test_hierarchy.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -591,7 +591,7 @@ "Tests is_valid_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3) with negative indices (left)." for i in xrange(4, 15, 3): y = np.random.rand(i*(i-1)/2) - Z = linkage(y) + Z = linkage(y) Z[int(i/2),0] = -2 self.failUnless(is_valid_linkage(Z) == False) self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True) @@ -600,7 +600,7 @@ "Tests is_valid_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3) with negative indices (right)." for i in xrange(4, 15, 3): y = np.random.rand(i*(i-1)/2) - Z = linkage(y) + Z = linkage(y) Z[int(i/2),1] = -2 self.failUnless(is_valid_linkage(Z) == False) self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True) @@ -609,7 +609,7 @@ "Tests is_valid_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3) with negative distances." for i in xrange(4, 15, 3): y = np.random.rand(i*(i-1)/2) - Z = linkage(y) + Z = linkage(y) Z[int(i/2),2] = -0.5 self.failUnless(is_valid_linkage(Z) == False) self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True) @@ -618,7 +618,7 @@ "Tests is_valid_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3) with negative counts." for i in xrange(4, 15, 3): y = np.random.rand(i*(i-1)/2) - Z = linkage(y) + Z = linkage(y) Z[int(i/2),3] = -2 self.failUnless(is_valid_linkage(Z) == False) self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True) @@ -676,7 +676,7 @@ for i in xrange(4, 15, 3): y = np.random.rand(i*(i-1)/2) Z = linkage(y) - R = inconsistent(Z) + R = inconsistent(Z) R[int(i/2),0] = -2.0 self.failUnless(is_valid_im(R) == False) self.failUnlessRaises(ValueError, is_valid_im, R, throw=True) @@ -686,7 +686,7 @@ for i in xrange(4, 15, 3): y = np.random.rand(i*(i-1)/2) Z = linkage(y) - R = inconsistent(Z) + R = inconsistent(Z) R[int(i/2),1] = -2.0 self.failUnless(is_valid_im(R) == False) self.failUnlessRaises(ValueError, is_valid_im, R, throw=True) @@ -696,7 +696,7 @@ for i in xrange(4, 15, 3): y = np.random.rand(i*(i-1)/2) Z = linkage(y) - R = inconsistent(Z) + R = inconsistent(Z) R[int(i/2),2] = -0.5 self.failUnless(is_valid_im(R) == False) self.failUnlessRaises(ValueError, is_valid_im, R, throw=True) Modified: trunk/scipy/interpolate/tests/test_fitpack.py =================================================================== --- trunk/scipy/interpolate/tests/test_fitpack.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/interpolate/tests/test_fitpack.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -155,12 +155,12 @@ y = array([1,2,3,4,5]) z = array([[1,2,1,2,1],[1,2,1,2,1],[1,2,3,2,1],[1,2,2,2,1],[1,2,1,2,1]]) lut = RectBivariateSpline(x,y,z) - + xi = [1, 2.3, 5.3, 0.5, 3.3, 1.2, 3] yi = [1, 3.3, 1.2, 4.0, 5.0, 1.0, 3] zi = lut.ev(xi, yi) zi2 = array([lut(xp, yp)[0,0] for xp, yp in zip(xi, yi)]) - + assert_almost_equal(zi, zi2) if __name__ == "__main__": Modified: trunk/scipy/io/matlab/tests/test_mio.py =================================================================== --- trunk/scipy/io/matlab/tests/test_mio.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/io/matlab/tests/test_mio.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -347,6 +347,5 @@ savemat(StringIO(), {'longstruct': st1}, format='5') fldname = 'a' * (lim+1) st1 = np.zeros((1,1), dtype=[(fldname, object)]) - assert_raises(ValueError, savemat, StringIO(), + assert_raises(ValueError, savemat, StringIO(), {'longstruct': st1}, format='5') - Modified: trunk/scipy/linalg/decomp.py =================================================================== --- trunk/scipy/linalg/decomp.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/linalg/decomp.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -1175,7 +1175,7 @@ warn("qr econ argument will be removed after scipy 0.7. " "The economy transform will then be available through " "the mode='economic' argument.", DeprecationWarning) - + a1 = asarray_chkfinite(a) if len(a1.shape) != 2: raise ValueError("expected 2D array") Modified: trunk/scipy/signal/signaltools.py =================================================================== --- trunk/scipy/signal/signaltools.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/signal/signaltools.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -1515,11 +1515,11 @@ #Based on: # [Gust96] Fredrik Gustafsson, Determining the initial states in # forward-backward filtering, IEEE Transactions on - # Signal Processing, pp. 988--992, April 1996, + # Signal Processing, pp. 988--992, April 1996, # Volume 44, Issue 4 n=max(len(a),len(b)) - + zin = (np.eye(n-1) - np.hstack((-a[1:n,newaxis], np.vstack((np.eye(n-2),zeros(n-2)))))) @@ -1530,12 +1530,12 @@ #convert the result into a regular array (not a matrix) for i in range(len(zi_matrix)): - zi_return.append(float(zi_matrix[i][0])) + zi_return.append(float(zi_matrix[i][0])) return array(zi_return) - + def filtfilt(b,a,x): # FIXME: For now only accepting 1d arrays ntaps=max(len(a),len(b)) Modified: trunk/scipy/sparse/linalg/eigen/arpack/setup.py =================================================================== --- trunk/scipy/sparse/linalg/eigen/arpack/setup.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/sparse/linalg/eigen/arpack/setup.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -43,11 +43,11 @@ config.add_library('arpack', sources=arpack_sources, include_dirs=[join('ARPACK', 'SRC')], - depends = [join('ARPACK', 'FWRAPPERS', + depends = [join('ARPACK', 'FWRAPPERS', 'veclib_cabi_f.f'), join('ARPACK', 'FWRAPPERS', 'veclib_cabi_c.c'), - join('ARPACK', 'FWRAPPERS', + join('ARPACK', 'FWRAPPERS', 'dummy.f')]) Modified: trunk/scipy/stats/distributions.py =================================================================== --- trunk/scipy/stats/distributions.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/stats/distributions.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -772,7 +772,7 @@ Parameters: ----------- n: int, n>=1 - + *args: The shape parameter(s) for the distribution (see docstring of the instance object for more information) @@ -3112,7 +3112,7 @@ def _ppf(self, q, b): return -log(1-q+q*exp(-b)) def _munp(self, n, b): - #wrong answer with formula, same as in continuous.pdf + #wrong answer with formula, same as in continuous.pdf #return gam(n+1)-special.gammainc(1+n,b) if n == 1: return (1-(b+1)*np.exp(-b))/(1-np.exp(-b)) @@ -3955,7 +3955,7 @@ Parameters: ----------- n: int, n>=1 - + *args: The shape parameter(s) for the distribution (see docstring of the instance object for more information) Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/stats/stats.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -1898,11 +1898,11 @@ Returns: t-value, two-tailed p-value This is a two-sided test for the null hypothesis that 2 independent samples - have identical average (expected) values. + have identical average (expected) values. Description ----------- - + We can use this test, if we observe two independent samples from the same or different population, e.g. exam scores of boys and girls or of two ethnic groups. The test measures whether the @@ -1966,12 +1966,12 @@ first), or an integer (the axis over which to operate on a and b). Returns: t-value, two-tailed p-value - + Description ----------- This is a two-sided test for the null hypothesis that 2 repeated samples - have identical average values. + have identical average values. Examples for the use are scores of a student in different exams, or repeated sampling from the same units. The test measures @@ -1984,7 +1984,7 @@ equal averages. see: http://en.wikipedia.org/wiki/T-test#Dependent_t-test - + Examples -------- @@ -2071,8 +2071,8 @@ defines distribution used for calculating p-value 'approx' : use approximation to exact distribution of test statistic 'asymp' : use asymptotic distribution of test statistic - + Returns ------- D: test statistic either D, D+ or D- @@ -2103,8 +2103,8 @@ --------------------------------------------- >>> np.random.seed(987654321) >>> # shift distribution to larger values, so that cdf_dgp(x)< norm.cdf(x) - >>> x = stats.norm.rvs(loc=0.2, size=100) - >>> kstest(x,'norm', alternative = 'smaller') + >>> x = stats.norm.rvs(loc=0.2, size=100) + >>> kstest(x,'norm', alternative = 'smaller') (0.12464329735846891, 0.040989164077641749) >>> # reject equal distribution against alternative hypothesis: smaller >>> kstest(x,'norm', alternative = 'larger') @@ -2112,24 +2112,24 @@ >>> # don't reject equal distribution against alternative hypothesis: larger >>> kstest(x,'norm', mode='asymp') (0.12464329735846891, 0.08944488871182088) - + testing t distributed random variables against normal distribution ------------------------------------------------------------------ With 100 degrees of freedom the t distribution looks close to the normal distribution, and the kstest does not reject the hypothesis that the sample came from the normal distribution - + >>> np.random.seed(987654321) >>> stats.kstest(stats.t.rvs(100,size=100),'norm') (0.072018929165471257, 0.67630062862479168) - + With 3 degrees of freedom the t distribution looks sufficiently different from the normal distribution, that we can reject the hypothesis that the sample came from the normal distribution at a alpha=10% level - + >>> np.random.seed(987654321) >>> stats.kstest(stats.t.rvs(3,size=100),'norm') (0.131016895759829, 0.058826222555312224) @@ -2139,11 +2139,11 @@ #cdf = getattr(stats, rvs).cdf if (not cdf) or (cdf == rvs): cdf = getattr(distributions, rvs).cdf - rvs = getattr(distributions, rvs).rvs + rvs = getattr(distributions, rvs).rvs else: raise AttributeError, 'if rvs is string, cdf has to be the same distribution' - - + + if isinstance(cdf, basestring): cdf = getattr(distributions, cdf).cdf if callable(rvs): @@ -2153,21 +2153,21 @@ vals = np.sort(rvs) N = len(vals) cdfvals = cdf(vals, *args) - + if alternative in ['unequal', 'larger']: Dplus = (np.arange(1.0, N+1)/N - cdfvals).max() if alternative == 'larger': return Dplus, distributions.ksone.sf(Dplus,N) - + if alternative in ['unequal', 'smaller']: Dmin = (cdfvals - np.arange(0.0, N)/N).max() if alternative == 'smaller': return Dmin, distributions.ksone.sf(Dmin,N) - + if alternative == 'unequal': D = np.max([Dplus,Dmin]) if mode == 'asymp': - return D, distributions.kstwobign.sf(D*np.sqrt(N)) + return D, distributions.kstwobign.sf(D*np.sqrt(N)) if mode == 'approx': pval_two = distributions.kstwobign.sf(D*np.sqrt(N)) if N > 2666 or pval_two > 0.80 - N*0.3/1000.0 : @@ -2198,7 +2198,7 @@ data1, data2: array_like, 1-dim samples assumed to be drawn from a continuous distribution, sample sizes can be different - + Returns: KS D-value, p-value Description: @@ -2207,7 +2207,7 @@ Tests whether 2 samples are drawn from the same distribution. Note that, like the one-sample K-S test the distribution is assumed to be continuous. - + This is the two-sided test, one-sided tests are not implemented. The test uses the two-sided asymptotic Kolmogorov-Smirnov distribution. @@ -2221,7 +2221,7 @@ >>> from scipy import stats >>> import numpy as np >>> from scipy.stats import ks_2samp - + # fix random seed to get the same result >>> np.random.seed(12345678); @@ -2247,7 +2247,7 @@ >>> rvs4 = stats.norm.rvs(size=n2,loc=0.0,scale=1.0) >>> ks_2samp(rvs1,rvs4) (0.07999999999999996, 0.41126949729859719) - + """ data1, data2 = map(asarray, (data1, data2)) n1 = data1.shape[0] Modified: trunk/scipy/stats/tests/test_discrete_basic.py =================================================================== --- trunk/scipy/stats/tests/test_discrete_basic.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/stats/tests/test_discrete_basic.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -47,7 +47,7 @@ alpha = 0.01 yield check_discrete_chisquare, distfn, arg, rvs, alpha, \ distname + ' chisquare' - + @npt.dec.slow def test_discrete_extra(): for distname, arg in distdiscrete: Modified: trunk/scipy/stats/tests/test_stats.py =================================================================== --- trunk/scipy/stats/tests/test_stats.py 2008-12-07 22:06:29 UTC (rev 5235) +++ trunk/scipy/stats/tests/test_stats.py 2008-12-08 00:08:23 UTC (rev 5236) @@ -999,7 +999,7 @@ def test_kstest(): #from numpy.testing import assert_almost_equal - + # comparing with values from R x = np.linspace(-1,1,9) D,p = stats.kstest(x,'norm') @@ -1052,7 +1052,7 @@ assert_almost_equal( np.array(stats.ks_2samp(np.linspace(1,100,100), np.linspace(1,100,110)+20-0.1)), - np.array((0.20818181818181825, 0.017981441789762638))) + np.array((0.20818181818181825, 0.017981441789762638))) if __name__ == "__main__": run_module_suite() From scipy-svn at scipy.org Mon Dec 8 14:46:55 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Mon, 8 Dec 2008 13:46:55 -0600 (CST) Subject: [Scipy-svn] r5237 - in trunk/scipy/io/matlab: . tests Message-ID: <20081208194655.A8F92C7C007@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-08 13:46:52 -0600 (Mon, 08 Dec 2008) New Revision: 5237 Modified: trunk/scipy/io/matlab/mio.py trunk/scipy/io/matlab/mio5.py trunk/scipy/io/matlab/miobase.py trunk/scipy/io/matlab/tests/test_mio.py Log: Committed nice patch to allow option for long field names, from Lee Kamentsky via Vebjorn Ljosa Modified: trunk/scipy/io/matlab/mio.py =================================================================== --- trunk/scipy/io/matlab/mio.py 2008-12-08 00:08:23 UTC (rev 5236) +++ trunk/scipy/io/matlab/mio.py 2008-12-08 19:46:52 UTC (rev 5237) @@ -116,7 +116,7 @@ return mdict @filldoc -def savemat(file_name, mdict, appendmat=True, format='5'): +def savemat(file_name, mdict, appendmat=True, format='5', long_field_names=False): """Save a dictionary of names and arrays into the MATLAB-style .mat file. This saves the arrayobjects in the given dictionary to a matlab @@ -130,7 +130,8 @@ %(append_arg)s format : {'5', '4'} string, optional '5' for matlab 5 (up to matlab 7.2) - '4' for matlab 4 mat files, + '4' for matlab 4 mat files + %(long_fields)s """ file_is_string = isinstance(file_name, basestring) if file_is_string: @@ -146,9 +147,13 @@ file_stream = file_name if format == '4': + if long_field_names: + raise ValueError("Long field names are not available for version 4 files") MW = MatFile4Writer(file_stream) elif format == '5': - MW = MatFile5Writer(file_stream, unicode_strings=True) + MW = MatFile5Writer(file_stream, + unicode_strings=True, + long_field_names=long_field_names) else: raise ValueError("Format should be '4' or '5'") MW.put_variables(mdict) Modified: trunk/scipy/io/matlab/mio5.py =================================================================== --- trunk/scipy/io/matlab/mio5.py 2008-12-08 00:08:23 UTC (rev 5236) +++ trunk/scipy/io/matlab/mio5.py 2008-12-08 19:46:52 UTC (rev 5237) @@ -631,10 +631,12 @@ arr, name, is_global=False, - unicode_strings=False): + unicode_strings=False, + long_field_names=False): super(Mat5MatrixWriter, self).__init__(file_stream, arr, name) self.is_global = is_global self.unicode_strings = unicode_strings + self.long_field_names = long_field_names def write_dtype(self, arr): self.file_stream.write(arr.tostring()) @@ -815,9 +817,10 @@ # write fieldnames fieldnames = [f[0] for f in self.arr.dtype.descr] length = max([len(fieldname) for fieldname in fieldnames])+1 - if length > 32: + max_length = (self.long_field_names and 64) or 32 + if length > max_length: raise ValueError( - "Field names are restricted to 64 characters in Matlab") + "Field names are restricted to %d characters in Matlab"%(max_length-1)) self.write_element(np.array([length], dtype='i4')) self.write_element( np.array(fieldnames, dtype='S%d'%(length)), @@ -842,9 +845,10 @@ class Mat5WriterGetter(object): ''' Wraps stream and options, provides methods for getting Writer objects ''' - def __init__(self, stream, unicode_strings): + def __init__(self, stream, unicode_strings, long_field_names=False): self.stream = stream self.unicode_strings = unicode_strings + self.long_field_names = long_field_names def rewind(self): self.stream.seek(0) @@ -871,7 +875,12 @@ # No interesting conversion possible raise TypeError('Could not convert %s (type %s) to array' % (arr, type(arr))) - args = (self.stream, narr, name, is_global, self.unicode_strings) + args = (self.stream, + narr, + name, + is_global, + self.unicode_strings, + self.long_field_names) if isinstance(narr, MatlabFunction): return Mat5FunctionWriter(*args) if isinstance(narr, MatlabObject): @@ -895,7 +904,8 @@ def __init__(self, file_stream, do_compression=False, unicode_strings=False, - global_vars=None): + global_vars=None, + long_field_names=False): super(MatFile5Writer, self).__init__(file_stream) self.do_compression = do_compression if global_vars: @@ -904,7 +914,8 @@ self.global_vars = [] self.writer_getter = Mat5WriterGetter( StringIO(), - unicode_strings) + unicode_strings, + long_field_names) # write header import os, time hdr = np.zeros((), mdtypes_template['file_header']) @@ -923,6 +934,15 @@ None, 'get/set unicode strings property') + def get_long_field_names(self): + return self.write_getter.long_field_names + def set_long_field_names(self, long_field_names): + self.writer_getter.long_field_names = long_field_names + long_field_names = property(get_long_field_names, + set_long_field_names, + None, + 'enable writing 32-63 character field names for Matlab 7.6+') + def put_variables(self, mdict): for name, var in mdict.items(): if name[0] == '_': Modified: trunk/scipy/io/matlab/miobase.py =================================================================== --- trunk/scipy/io/matlab/miobase.py 2008-12-08 00:08:23 UTC (rev 5236) +++ trunk/scipy/io/matlab/miobase.py 2008-12-08 19:46:52 UTC (rev 5237) @@ -57,7 +57,13 @@ Note that non-record arrays cannot be exported via savemat.''', 'matstream_arg': '''mat_stream : file-like - object with file API, open for reading'''} + object with file API, open for reading''', + 'long_fields': + '''long_field_names : boolean, optional, default=False + False - maximum field name length in a structure is 31 characters + which is the documented maximum length + True - maximum field name length in a structure is 63 characters + which works for Matlab 7.6'''} func.__doc__ = func.__doc__ % doc_dict return func Modified: trunk/scipy/io/matlab/tests/test_mio.py =================================================================== --- trunk/scipy/io/matlab/tests/test_mio.py 2008-12-08 00:08:23 UTC (rev 5236) +++ trunk/scipy/io/matlab/tests/test_mio.py 2008-12-08 19:46:52 UTC (rev 5237) @@ -338,6 +338,7 @@ """Regression test for #653.""" assert_raises(TypeError, savemat, StringIO(), {'d':{1:2}}, format='5') + def test_structname_len(): # Test limit for length of field names in structs lim = 31 @@ -349,3 +350,23 @@ st1 = np.zeros((1,1), dtype=[(fldname, object)]) assert_raises(ValueError, savemat, StringIO(), {'longstruct': st1}, format='5') + + +def test_4_and_long_field_names_incompatible(): + # Long field names option not supported in 4 + my_struct = np.zeros((1,1),dtype=[('my_fieldname',object)]) + assert_raises(ValueError, savemat, StringIO(), + {'my_struct':my_struct}, format='4', long_field_names=True) + + +def test_long_field_names(): + # Test limit for length of field names in structs + lim = 63 + fldname = 'a' * lim + st1 = np.zeros((1,1), dtype=[(fldname, object)]) + mat_stream = StringIO() + savemat(StringIO(), {'longstruct': st1}, format='5',long_field_names=True) + fldname = 'a' * (lim+1) + st1 = np.zeros((1,1), dtype=[(fldname, object)]) + assert_raises(ValueError, savemat, StringIO(), + {'longstruct': st1}, format='5',long_field_names=True) From scipy-svn at scipy.org Tue Dec 9 10:08:15 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 9 Dec 2008 09:08:15 -0600 (CST) Subject: [Scipy-svn] r5238 - trunk/doc/release Message-ID: <20081209150815.13EE3C7C00D@scipy.org> Author: josef Date: 2008-12-09 09:08:09 -0600 (Tue, 09 Dec 2008) New Revision: 5238 Modified: trunk/doc/release/0.7.0-notes.rst Log: add stats changes to release notes Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-08 19:46:52 UTC (rev 5237) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-09 15:08:09 UTC (rev 5238) @@ -175,6 +175,31 @@ Users of ``scipy.interpolate.interp1d`` may need to revise their code if it relies on the incorrect behavior. +Bug fixes in the stats package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Statistical functions for masked arrays have been added and are accessible +through scipy.stats.mstats. The functions are similar to their counterparts +in scipy.stats but they have not yet been verified for identical interfaces +and algorithms. + +Several bugs were fixed for statistical functions, of those, kstest and percentileofscore +gained new keyword arguments. + +Added deprecation warning for mean, median, var, std, cov and corrcoef. These functions +should be replaced by their numpy counterparts. Note, however, that some of the default +options differ between the scipy.stats and numpy versions of these functions. + +Numerous bug fixes to stats.distributions: all generic methods work now correctly, several +methods in individual distributions were corrected. However, a few issues remain with +higher moments (skew, kurtosis) and entropy. The maximum likelihood estimator, fit, does not +work out-of-the-box for some distributions, in some cases, starting values have to be +carefully chosen, in other cases, the generic implementation of the maximum likelihood +method might not be the numerically appropriate estimation method. + +We expect more bugfixes, increases in numerical precision and enhancements in the next +release of scipy. + Running Tests ~~~~~~~~~~~~~ From scipy-svn at scipy.org Tue Dec 9 19:59:42 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 9 Dec 2008 18:59:42 -0600 (CST) Subject: [Scipy-svn] r5239 - trunk/doc/source Message-ID: <20081210005942.B4A3039C088@scipy.org> Author: damian.eads Date: 2008-12-09 18:59:30 -0600 (Tue, 09 Dec 2008) New Revision: 5239 Modified: trunk/doc/source/spatial.rst Log: Tweaked scipy.spatial header so it is more general than just distance computations. Modified: trunk/doc/source/spatial.rst =================================================================== --- trunk/doc/source/spatial.rst 2008-12-09 15:08:09 UTC (rev 5238) +++ trunk/doc/source/spatial.rst 2008-12-10 00:59:30 UTC (rev 5239) @@ -1,6 +1,6 @@ -============================================ -Distance computations (:mod:`scipy.spatial`) -============================================ +============================================================= +Spatial algorithms and data structures (:mod:`scipy.spatial`) +============================================================= .. warning:: From scipy-svn at scipy.org Tue Dec 9 20:16:54 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 9 Dec 2008 19:16:54 -0600 (CST) Subject: [Scipy-svn] r5240 - trunk/doc/release Message-ID: <20081210011654.8F78E39C088@scipy.org> Author: damian.eads Date: 2008-12-09 19:16:53 -0600 (Tue, 09 Dec 2008) New Revision: 5240 Modified: trunk/doc/release/0.7.0-notes.rst Log: Wordsmithed hierarchy section of 0.7.0 release notes. Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-10 00:59:30 UTC (rev 5239) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-10 01:16:53 UTC (rev 5240) @@ -85,8 +85,13 @@ transform a hierarchical clustering into a set of flat clusters. Since these flat clusters are generated by cutting the tree into a forest of trees, the ``leaders`` function takes a linkage and a flat clustering -and finds the root of each tree in the forest. Finally, a matplotlib -extension is provided for plotting dendrograms. +and finds the root of each tree in the forest. The ``ClusterNode`` +class represents a hierarchical clusterings as a field-navigable tree +object. ``to_tree`` converts a matrix-encoded hierarchical clustering +to a ``ClusterNode`` object. Routines for converting between MATLAB +and SciPy linkage encodings are provided. Finally, a ``dendrogram`` +function plots hierarchical clusterings as a dendrogram using +matplotlib. New Spatial package ~~~~~~~~~~~~~~~~~~~ @@ -112,7 +117,7 @@ the distance on all pairs of vectors in the Cartesian product of two sets of vectors. Pairwise distance matrices are stored in condensed form, only the upper triangular is stored. ``squareform`` converts -between square distance matrices and condensed distance matrices. +distance matrices between square and condensed forms. Reworked fftpack package ~~~~~~~~~~~~~~~~~~~~~~~~ From scipy-svn at scipy.org Wed Dec 10 15:45:48 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 10 Dec 2008 14:45:48 -0600 (CST) Subject: [Scipy-svn] r5241 - in trunk/scipy/stats: . tests Message-ID: <20081210204548.A7CC2C7C031@scipy.org> Author: josef Date: 2008-12-10 14:45:44 -0600 (Wed, 10 Dec 2008) New Revision: 5241 Modified: trunk/scipy/stats/stats.py trunk/scipy/stats/tests/test_stats.py Log: change kstest option names to match mstats.ks_twosamp (same as R) Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-10 01:16:53 UTC (rev 5240) +++ trunk/scipy/stats/stats.py 2008-12-10 20:45:44 UTC (rev 5241) @@ -2034,16 +2034,16 @@ #import scipy.stats #import distributions -def kstest(rvs, cdf, args=(), N=20, alternative = 'unequal', mode='approx'): +def kstest(rvs, cdf, args=(), N=20, alternative = 'two_sided', mode='approx',**kwds): """Return the D-value and the p-value for a Kolmogorov-Smirnov test This performs a test of the distribution of random variables G(x) against a given distribution F(x). Under the null hypothesis the two distributions are identical, G(x)=F(x). The alternative hypothesis can be either - 'unequal' (default), 'smaller' or 'larger'. In the two one-sided test, + 'two_sided' (default), 'less' or 'greater'. In the two one-sided test, the alternative is that the empirical cumulative distribution function, - of the random variable is "smaller" or "larger" then the cumulative + of the random variable is "less" or "greater" then the cumulative distribution function of the hypothesis F(x), G(x)<=F(x), resp. G(x)>=F(x). If the p-value is greater than the significance level (say 5%), then we @@ -2065,7 +2065,7 @@ args : distribution parameters used if rvs or cdf are strings N : sample size if rvs is string or callable - alternative : 'unequal' (default), 'smaller' or 'larger' + alternative : 'two_sided' (default), 'less' or 'greater' defines the alternative hypothesis (see explanation) mode : 'approx' (default) or 'asymp' defines distribution used for calculating p-value @@ -2103,13 +2103,13 @@ --------------------------------------------- >>> np.random.seed(987654321) >>> # shift distribution to larger values, so that cdf_dgp(x)< norm.cdf(x) - >>> x = stats.norm.rvs(loc=0.2, size=100) - >>> kstest(x,'norm', alternative = 'smaller') + >>> x = stats.norm.rvs(loc=0.2, size=100) + >>> kstest(x,'norm', alternative = 'less') (0.12464329735846891, 0.040989164077641749) - >>> # reject equal distribution against alternative hypothesis: smaller - >>> kstest(x,'norm', alternative = 'larger') + >>> # reject equal distribution against alternative hypothesis: less + >>> kstest(x,'norm', alternative = 'greater') (0.0072115233216311081, 0.98531158590396395) - >>> # don't reject equal distribution against alternative hypothesis: larger + >>> # don't reject equal distribution against alternative hypothesis: greater >>> kstest(x,'norm', mode='asymp') (0.12464329735846891, 0.08944488871182088) @@ -2154,17 +2154,17 @@ N = len(vals) cdfvals = cdf(vals, *args) - if alternative in ['unequal', 'larger']: + if alternative in ['two_sided', 'greater']: Dplus = (np.arange(1.0, N+1)/N - cdfvals).max() - if alternative == 'larger': + if alternative == 'greater': return Dplus, distributions.ksone.sf(Dplus,N) - if alternative in ['unequal', 'smaller']: + if alternative in ['two_sided', 'less']: Dmin = (cdfvals - np.arange(0.0, N)/N).max() - if alternative == 'smaller': + if alternative == 'less': return Dmin, distributions.ksone.sf(Dmin,N) - if alternative == 'unequal': + if alternative == 'two_sided': D = np.max([Dplus,Dmin]) if mode == 'asymp': return D, distributions.kstwobign.sf(D*np.sqrt(N)) Modified: trunk/scipy/stats/tests/test_stats.py =================================================================== --- trunk/scipy/stats/tests/test_stats.py 2008-12-10 01:16:53 UTC (rev 5240) +++ trunk/scipy/stats/tests/test_stats.py 2008-12-10 20:45:44 UTC (rev 5241) @@ -1019,9 +1019,9 @@ assert_almost_equal( p, 0.089444888711820769, 15) assert_almost_equal( np.array(stats.kstest(x, 'norm', mode='asymp')), np.array((0.12464329735846891, 0.089444888711820769)), 15) - assert_almost_equal( np.array(stats.kstest(x,'norm', alternative = 'smaller')), + assert_almost_equal( np.array(stats.kstest(x,'norm', alternative = 'less')), np.array((0.12464329735846891, 0.040989164077641749)), 15) - assert_almost_equal( np.array(stats.kstest(x,'norm', alternative = 'larger')), + assert_almost_equal( np.array(stats.kstest(x,'norm', alternative = 'greater')), np.array((0.0072115233216310994, 0.98531158590396228)), 14) #missing: no test that uses *args From scipy-svn at scipy.org Thu Dec 11 19:50:05 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 11 Dec 2008 18:50:05 -0600 (CST) Subject: [Scipy-svn] r5242 - trunk Message-ID: <20081212005005.C2128C7C019@scipy.org> Author: damian.eads Date: 2008-12-11 18:50:03 -0600 (Thu, 11 Dec 2008) New Revision: 5242 Modified: trunk/THANKS.txt Log: Added a few names of core contributors from the top of my head. I may have forgotten someone. Modified: trunk/THANKS.txt =================================================================== --- trunk/THANKS.txt 2008-12-10 20:45:44 UTC (rev 5241) +++ trunk/THANKS.txt 2008-12-12 00:50:03 UTC (rev 5242) @@ -31,9 +31,12 @@ Jeff Whitaker -- Mac OS X support David Cournapeau -- bug-fixes, refactor of fftpack and cluster, numscons build. Damian Eads -- hierarchical clustering, dendrogram plotting, - distance functions, vq documentation + distance functions in spatial package, vq documentation +Anne Archibald -- kd-trees and nearest neighbor in scipy.spatial +Pauli Virtanen -- Sphinx documentation generation, interpolation, + and scipy.nonlin.optimize rewrite. +Josef Pktd -- major improvements to scipy.stats and its test suite - Testing: David Morrill for getting the scoreboard test system up and running. From scipy-svn at scipy.org Thu Dec 11 21:54:27 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 11 Dec 2008 20:54:27 -0600 (CST) Subject: [Scipy-svn] r5243 - trunk/scipy/spatial Message-ID: <20081212025427.4DBD5C7C011@scipy.org> Author: damian.eads Date: 2008-12-11 20:54:24 -0600 (Thu, 11 Dec 2008) New Revision: 5243 Modified: trunk/scipy/spatial/distance.py Log: Fixed bugs in LaTeX math in distance documentation. Modified: trunk/scipy/spatial/distance.py =================================================================== --- trunk/scipy/spatial/distance.py 2008-12-12 00:50:03 UTC (rev 5242) +++ trunk/scipy/spatial/distance.py 2008-12-12 02:54:24 UTC (rev 5243) @@ -370,8 +370,8 @@ .. math:: - \frac{c_{TF} + c_{FT}} - {c_{TT} + c_{FT} + c_{TF}} + \frac{c_{TF} + c_{FT}} + {c_{TT} + c_{FT} + c_{TF}} where :math:`c_{ij}` is the number of occurrences of :math:`\mathtt{u[k]} = i` and :math:`\mathtt{v[k]} = j` for @@ -400,8 +400,8 @@ .. math:: - \frac{c_{TF} + c_{FT} - c_{TT} + n} - {c_{FT} + c_{TF} + n} + \frac{c_{TF} + c_{FT} - c_{TT} + n} + {c_{FT} + c_{TF} + n} where :math:`c_{ij}` is the number of occurrences of :math:`\mathtt{u[k]} = i` and :math:`\mathtt{v[k]} = j` for @@ -455,7 +455,7 @@ .. math:: - \sum_i {u_i-v_i}. + \sum_i {(u_i-v_i)}. :Parameters: u : ndarray @@ -872,7 +872,7 @@ 5. ``Y = pdist(X, 'sqeuclidean')`` - Computes the squared Euclidean distance ||u-v||_2^2 between + Computes the squared Euclidean distance :math:`||u-v||_2^2` between the vectors. 6. ``Y = pdist(X, 'cosine')`` @@ -920,7 +920,7 @@ .. math:: - d(u,v) = max_i {|u_i-v_i|}. + d(u,v) = \max_i {|u_i-v_i|}. 11. ``Y = pdist(X, 'canberra')`` @@ -929,8 +929,8 @@ .. math:: - d(u,v) = \sum_u {|u_i-v_i|} - {|u_i|+|v_i|} + d(u,v) = \sum_u \frac{|u_i-v_i|} + {(|u_i|+|v_i|)} 12. ``Y = pdist(X, 'braycurtis')`` @@ -1043,8 +1043,11 @@ Y : ndarray A condensed distance matrix. + :SeeAlso: - """ + squareform : converts between condensed distance matrices and + square distance matrices. + """ # 21. Y = pdist(X, 'test_Y') @@ -1603,7 +1606,7 @@ 5. ``Y = cdist(XA, XB, 'sqeuclidean')`` - Computes the squared Euclidean distance ||u-v||_2^2 between + Computes the squared Euclidean distance :math:`||u-v||_2^2` between the vectors. 6. ``Y = cdist(XA, XB, 'cosine')`` @@ -1615,7 +1618,7 @@ \frac{1 - uv^T} {{|u|}_2 {|v|}_2} - where |*|_2 is the 2 norm of its argument *. + where :math:`|*|_2` is the 2-norm of its argument *. 7. ``Y = cdist(XA, XB, 'correlation')`` @@ -1653,7 +1656,7 @@ .. math:: - d(u,v) = max_i {|u_i-v_i|}. + d(u,v) = \max_i {|u_i-v_i|}. 11. ``Y = cdist(XA, XB, 'canberra')`` @@ -1662,8 +1665,8 @@ .. math:: - d(u,v) = \sum_u {|u_i-v_i|} - {|u_i|+|v_i|} + d(u,v) = \sum_u \frac{|u_i-v_i|} + {(|u_i|+|v_i|)} 12. ``Y = cdist(XA, XB, 'braycurtis')`` @@ -1674,8 +1677,8 @@ .. math:: - d(u,v) = \frac{\sum_i {u_i-v_i}} - {\sum_i {u_i+v_i}} + d(u,v) = \frac{\sum_i (u_i-v_i)} + {\sum_i (u_i+v_i)} 13. ``Y = cdist(XA, XB, 'mahalanobis', VI=None)`` @@ -1687,38 +1690,38 @@ 14. ``Y = cdist(XA, XB, 'yule')`` - Computes the Yule distance between each pair of boolean + Computes the Yule distance between the boolean vectors. (see yule function documentation) - 15. ``Y = cdist(XA, 'matching')`` + 15. ``Y = cdist(XA, XB, 'matching')`` - Computes the matching distance between each pair of boolean + Computes the matching distance between the boolean vectors. (see matching function documentation) - 16. ``Y = cdist(XA, 'dice')`` + 16. ``Y = cdist(XA, XB, 'dice')`` - Computes the Dice distance between each pair of boolean - vectors. (see dice function documentation) + Computes the Dice distance between the boolean vectors. (see + dice function documentation) 17. ``Y = cdist(XA, XB, 'kulsinski')`` - Computes the Kulsinski distance between each pair of - boolean vectors. (see kulsinski function documentation) + Computes the Kulsinski distance between the boolean + vectors. (see kulsinski function documentation) 18. ``Y = cdist(XA, XB, 'rogerstanimoto')`` - Computes the Rogers-Tanimoto distance between each pair of - boolean vectors. (see rogerstanimoto function documentation) + Computes the Rogers-Tanimoto distance between the boolean + vectors. (see rogerstanimoto function documentation) 19. ``Y = cdist(XA, XB, 'russellrao')`` - Computes the Russell-Rao distance between each pair of - boolean vectors. (see russellrao function documentation) + Computes the Russell-Rao distance between the boolean + vectors. (see russellrao function documentation) 20. ``Y = cdist(XA, XB, 'sokalmichener')`` - Computes the Sokal-Michener distance between each pair of - boolean vectors. (see sokalmichener function documentation) + Computes the Sokal-Michener distance between the boolean + vectors. (see sokalmichener function documentation) 21. ``Y = cdist(XA, XB, 'sokalsneath')`` From scipy-svn at scipy.org Thu Dec 11 22:04:47 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 11 Dec 2008 21:04:47 -0600 (CST) Subject: [Scipy-svn] r5244 - trunk/scipy/cluster Message-ID: <20081212030447.CFF70C7C011@scipy.org> Author: damian.eads Date: 2008-12-11 21:04:43 -0600 (Thu, 11 Dec 2008) New Revision: 5244 Modified: trunk/scipy/cluster/hierarchy.py Log: Minor fixes in hierarchy documentation. Modified: trunk/scipy/cluster/hierarchy.py =================================================================== --- trunk/scipy/cluster/hierarchy.py 2008-12-12 02:54:24 UTC (rev 5243) +++ trunk/scipy/cluster/hierarchy.py 2008-12-12 03:04:43 UTC (rev 5244) @@ -333,13 +333,13 @@ The following are common calling conventions: - 1. Z = centroid(y) + 1. ``Z = centroid(y)`` Performs centroid/UPGMC linkage on the condensed distance matrix ``y``. See ``linkage`` for more information on the return structure and algorithm. - 2. Z = centroid(X) + 2. ``Z = centroid(X)`` Performs centroid/UPGMC linkage on the observation matrix ``X`` using Euclidean distance as the distance metric. See ``linkage`` @@ -372,13 +372,13 @@ The following are common calling conventions: - 1. Z = median(y) + 1. ``Z = median(y)`` Performs median/WPGMC linkage on the condensed distance matrix ``y``. See ``linkage`` for more information on the return structure and algorithm. - 2. Z = median(X) + 2. ``Z = median(X)`` Performs median/WPGMC linkage on the observation matrix ``X`` using Euclidean distance as the distance metric. See linkage @@ -410,13 +410,13 @@ The following are common calling conventions: - 1. Z = ward(y) - Performs Ward's linkage on the condensed distance matrix Z. See + 1. ``Z = ward(y)`` + Performs Ward's linkage on the condensed distance matrix ``Z``. See linkage for more information on the return structure and algorithm. - 2. Z = ward(X) - Performs Ward's linkage on the observation matrix X using + 2. ``Z = ward(X)`` + Performs Ward's linkage on the observation matrix ``X`` using Euclidean distance as the distance metric. See linkage for more information on the return structure and algorithm. @@ -484,7 +484,7 @@ The following are methods for calculating the distance between the newly formed cluster :math:`u` and each :math:`v`. - * method=``single`` assigns + * method='single' assigns .. math:: d(u,v) = \min(dist(u[i],v[j])) @@ -493,7 +493,7 @@ :math:`j` in cluster :math:`v`. This is also known as the Nearest Point Algorithm. - * method=``complete`` assigns + * method='complete' assigns .. math:: d(u, v) = \max(dist(u[i],v[j])) @@ -502,7 +502,7 @@ cluster :math:`v`. This is also known by the Farthest Point Algorithm or Voor Hees Algorithm. - * method=``average`` assigns + * method='average' assigns .. math:: d(u,v) = \sum_{ij} \frac{d(u[i], v[j])} @@ -524,7 +524,7 @@ * method='centroid' assigns .. math:: - dist(s,t) = euclid(c_s, c_t) + dist(s,t) = ||c_s-c_t||_2 where :math:`c_s` and :math:`c_t` are the centroids of clusters :math:`s` and :math:`t`, respectively. When two @@ -536,11 +536,11 @@ :math:`v` in the forest. This is also known as the UPGMC algorithm. - * method='median' assigns math:`$d(s,t)$` like the ``centroid`` - method. When two clusters s and t are combined into a new - cluster :math:`u`, the average of centroids s and t give the - new centroid :math:`u`. This is also known as the WPGMC - algorithm. + * method='median' assigns math:`d(s,t)` like the ``centroid`` + method. When two clusters :math:`s` and :math:`t` are combined + into a new cluster :math:`u`, the average of centroids s and t + give the new centroid :math:`u`. This is also known as the + WPGMC algorithm. * method='ward' uses the Ward variance minimization algorithm. The new entry :math:`d(u,v)` is computed as follows, @@ -633,7 +633,7 @@ :SeeAlso: - - to_tree: for converting a linkage matrix Z into a tree object. + - to_tree: for converting a linkage matrix ``Z`` into a tree object. """ def __init__(self, id, left=None, right=None, dist=0, count=1): @@ -781,7 +781,7 @@ def to_tree(Z, rd=False): """ - Converts a hierarchical clustering encoded in the matrix Z (by + Converts a hierarchical clustering encoded in the matrix ``Z`` (by linkage) into an easy-to-use tree object. The reference r to the root ClusterNode object is returned. @@ -1299,8 +1299,8 @@ def correspond(Z, Y): """ - Checks if a linkage matrix Z and condensed distance matrix - Y could possibly correspond to one another. + Checks if a linkage matrix ``Z`` and condensed distance matrix + ``Y`` could possibly correspond to one another. They must have the same number of original observations for the check to succeed. @@ -1464,7 +1464,6 @@ - t : double The threshold to apply when forming flat clusters. - - criterion : string Specifies the criterion for forming flat clusters. Valid values are 'inconsistent', 'distance', or 'maxclust' cluster @@ -1496,8 +1495,8 @@ :Returns: - T : ndarray - A vector of length ``n``. ``T[i]`` is the flat cluster number to - which original observation ``i`` belongs. + A vector of length ``n``. ``T[i]`` is the flat cluster number to + which original observation ``i`` belongs. Notes ----- From scipy-svn at scipy.org Sat Dec 13 16:19:44 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 13 Dec 2008 15:19:44 -0600 (CST) Subject: [Scipy-svn] r5245 - trunk/doc/frontpage/_templates Message-ID: <20081213211944.250E0C7C00E@scipy.org> Author: ptvirtan Date: 2008-12-13 15:19:02 -0600 (Sat, 13 Dec 2008) New Revision: 5245 Modified: trunk/doc/frontpage/_templates/indexcontent.html Log: frontpage: add links to CHM files Modified: trunk/doc/frontpage/_templates/indexcontent.html =================================================================== --- trunk/doc/frontpage/_templates/indexcontent.html 2008-12-12 03:04:43 UTC (rev 5244) +++ trunk/doc/frontpage/_templates/indexcontent.html 2008-12-13 21:19:02 UTC (rev 5245) @@ -18,14 +18,17 @@
    From scipy-svn at scipy.org Sat Dec 13 21:30:24 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 13 Dec 2008 20:30:24 -0600 (CST) Subject: [Scipy-svn] r5246 - in trunk/scipy/io/matlab: . tests Message-ID: <20081214023024.EBE95C7C00E@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-13 20:30:09 -0600 (Sat, 13 Dec 2008) New Revision: 5246 Modified: trunk/scipy/io/matlab/byteordercodes.py trunk/scipy/io/matlab/mio5.py trunk/scipy/io/matlab/tests/test_mio.py Log: Added tests, and reimplemented fixes, from Lee Kamnetsky; refactored option passing somewhat; removed remaining bare assert statements in tests Modified: trunk/scipy/io/matlab/byteordercodes.py =================================================================== --- trunk/scipy/io/matlab/byteordercodes.py 2008-12-13 21:19:02 UTC (rev 5245) +++ trunk/scipy/io/matlab/byteordercodes.py 2008-12-14 02:30:09 UTC (rev 5246) @@ -36,7 +36,6 @@ Examples -------- >>> import sys - >>> from imagers.byteorder import to_numpy_code, sys_is_le >>> sys_is_le == (sys.byteorder == 'little') True >>> to_numpy_code('big') Modified: trunk/scipy/io/matlab/mio5.py =================================================================== --- trunk/scipy/io/matlab/mio5.py 2008-12-13 21:19:02 UTC (rev 5245) +++ trunk/scipy/io/matlab/mio5.py 2008-12-14 02:30:09 UTC (rev 5246) @@ -622,10 +622,10 @@ class Mat5MatrixWriter(MatStreamWriter): - + ''' Generic matlab matrix writing class ''' mat_tag = np.zeros((), mdtypes_template['tag_full']) mat_tag['mdtype'] = miMATRIX - + default_mclass = None # default class for header writing def __init__(self, file_stream, arr, @@ -670,7 +670,7 @@ # pad to next 64-bit boundary self.write_bytes(np.zeros((padding,),'u1')) - def write_header(self, mclass, + def write_header(self, mclass=None, is_global=False, is_complex=False, is_logical=False, @@ -686,6 +686,8 @@ directly specify shape if this is not the same as for self.arr ''' + if mclass is None: + mclass = self.default_mclass if shape is None: shape = self.arr.shape if len(shape) < 2: @@ -712,10 +714,18 @@ self.file_stream.seek(curr_pos) def write(self): - assert False, 'Not implemented' + raise NotImplementedError + def make_writer_getter(self): + ''' Make writer getter for this stream ''' + return Mat5WriterGetter(self.file_stream, + self.unicode_strings, + self.long_field_names) + + class Mat5NumericWriter(Mat5MatrixWriter): + default_mclass = None # can be any numeric type def write(self): imagf = self.arr.dtype.kind == 'c' try: @@ -737,13 +747,14 @@ class Mat5CharWriter(Mat5MatrixWriter): codec='ascii' + default_mclass = mxCHAR_CLASS def write(self): self.arr_to_chars() # We have to write the shape directly, because we are going # recode the characters, and the resulting stream of chars # may have a different length shape = self.arr.shape - self.write_header(mclass=mxCHAR_CLASS,shape=shape) + self.write_header(shape=shape) # We need to do our own transpose (not using the normal # write routines that do this for us) arr = self.arr.T.copy() @@ -766,6 +777,7 @@ class Mat5SparseWriter(Mat5MatrixWriter): + default_mclass = mxSPARSE_CLASS def write(self): ''' Sparse matrices are 2D ''' @@ -773,8 +785,7 @@ A.sort_indices() # MATLAB expects sorted row indices is_complex = (A.dtype.kind == 'c') nz = A.nnz - self.write_header(mclass=mxSPARSE_CLASS, - is_complex=is_complex, + self.write_header(is_complex=is_complex, nzmax=nz) self.write_element(A.indices.astype('i4')) self.write_element(A.indptr.astype('i4')) @@ -785,49 +796,51 @@ class Mat5CellWriter(Mat5MatrixWriter): + default_mclass = mxCELL_CLASS def write(self): - self.write_header(mclass=mxCELL_CLASS) + self.write_header() + self._write_items() + + def _write_items(self): # loop over data, column major A = np.atleast_2d(self.arr).flatten('F') - MWG = Mat5WriterGetter(self.file_stream, self.unicode_strings) + MWG = self.make_writer_getter() for el in A: MW = MWG.matrix_writer_factory(el, '') MW.write() self.update_matrix_tag() -class Mat5FunctionWriter(Mat5MatrixWriter): - def write(self): - self.write_header(mclass=mxFUNCTION_CLASS) - # loop over data, column major - A = np.atleast_2d(self.arr).flatten('F') - MWG = Mat5WriterGetter(self.file_stream, self.unicode_strings) - for el in A: - MW = MWG.matrix_writer_factory(el, '') - MW.write() - self.update_matrix_tag() +class Mat5FunctionWriter(Mat5CellWriter): + ''' class to write matlab functions + Only differs from cell writing in mx class in header ''' + default_mclass = mxFUNCTION_CLASS -class Mat5StructWriter(Mat5MatrixWriter): - def write(self): - self.write_header(mclass=mxSTRUCT_CLASS) - self.write_fields() - def write_fields(self): +class Mat5StructWriter(Mat5CellWriter): + ''' class to write matlab structs + + Differs from cell writing class in writing field names, + and in mx class + ''' + default_mclass = mxSTRUCT_CLASS + + def _write_items(self): # write fieldnames fieldnames = [f[0] for f in self.arr.dtype.descr] length = max([len(fieldname) for fieldname in fieldnames])+1 max_length = (self.long_field_names and 64) or 32 if length > max_length: raise ValueError( - "Field names are restricted to %d characters in Matlab"%(max_length-1)) + "Field names are restricted to %d characters" + % (max_length-1)) self.write_element(np.array([length], dtype='i4')) self.write_element( np.array(fieldnames, dtype='S%d'%(length)), mdtype=miINT8) A = np.atleast_2d(self.arr).flatten('F') - MWG = Mat5WriterGetter(self.file_stream, - self.unicode_strings) + MWG = self.make_writer_getter() for el in A: for f in fieldnames: MW = MWG.matrix_writer_factory(el[f], '') @@ -836,11 +849,17 @@ class Mat5ObjectWriter(Mat5StructWriter): + ''' class to write matlab objects + + Same as writing structs, except different mx class, and extra + classname element after header + ''' + default_mclass = mxOBJECT_CLASS def write(self): - self.write_header(mclass=mxOBJECT_CLASS) + self.write_header() self.write_element(np.array(self.arr.classname, dtype='S'), mdtype=miINT8) - self.write_fields() + self._write_items() class Mat5WriterGetter(object): @@ -871,7 +890,7 @@ # Next try and convert to an array narr = np.asanyarray(arr) if narr.dtype.type in (np.object, np.object_) and \ - narr.size == 1 and narr == arr: + narr.shape == () and narr == arr: # No interesting conversion possible raise TypeError('Could not convert %s (type %s) to array' % (arr, type(arr))) @@ -926,7 +945,7 @@ file_stream.write(hdr.tostring()) def get_unicode_strings(self): - return self.write_getter.unicode_strings + return self.writer_getter.unicode_strings def set_unicode_strings(self, unicode_strings): self.writer_getter.unicode_strings = unicode_strings unicode_strings = property(get_unicode_strings, @@ -935,7 +954,7 @@ 'get/set unicode strings property') def get_long_field_names(self): - return self.write_getter.long_field_names + return self.writer_getter.long_field_names def set_long_field_names(self, long_field_names): self.writer_getter.long_field_names = long_field_names long_field_names = property(get_long_field_names, Modified: trunk/scipy/io/matlab/tests/test_mio.py =================================================================== --- trunk/scipy/io/matlab/tests/test_mio.py 2008-12-13 21:19:02 UTC (rev 5245) +++ trunk/scipy/io/matlab/tests/test_mio.py 2008-12-14 02:30:09 UTC (rev 5246) @@ -25,7 +25,7 @@ import scipy.sparse as SP from scipy.io.matlab.mio import loadmat, savemat, find_mat_file -from scipy.io.matlab.mio5 import MatlabObject +from scipy.io.matlab.mio5 import MatlabObject, MatFile5Writer test_data_path = join(dirname(__file__), 'data') @@ -196,7 +196,7 @@ def _check_level(label, expected, actual): """ Check one level of a potentially nested array """ if SP.issparse(expected): # allow different types of sparse matrices - assert SP.issparse(actual) + assert_true(SP.issparse(actual)) assert_array_almost_equal(actual.todense(), expected.todense(), err_msg = label, @@ -205,8 +205,8 @@ # Check types are as expected typex = type(expected) typac = type(actual) - assert typex is typac, \ - "Expected type %s, got %s at %s" % (typex, typac, label) + assert_true(typex is typac, \ + "Expected type %s, got %s at %s" % (typex, typac, label)) # A field in a record array may not be an ndarray # A scalar from a record array will be type np.void if not isinstance(expected, @@ -246,7 +246,7 @@ label = "test %s; file %s" % (name, file_name) for k, expected in case.items(): k_label = "%s, variable %s" % (label, k) - assert k in matdict, "Missing key at %s" % k_label + assert_true(k in matdict, "Missing key at %s" % k_label) _check_level(k_label, expected, matdict[k]) # Round trip tests @@ -264,7 +264,8 @@ expected = case['expected'] filt = join(test_data_path, 'test%s_*.mat' % name) files = glob(filt) - assert files, "No files for test %s using filter %s" % (name, filt) + assert_true(len(files) > 0, + "No files for test %s using filter %s" % (name, filt)) yield _load_check_case, name, files, expected @@ -308,7 +309,7 @@ # Check any hdf5 files raise an error filenames = glob( join(test_data_path, 'testhdf5*.mat')) - assert len(filenames) + assert_true(len(filenames)>0) for filename in filenames: assert_raises(NotImplementedError, loadmat, @@ -370,3 +371,49 @@ st1 = np.zeros((1,1), dtype=[(fldname, object)]) assert_raises(ValueError, savemat, StringIO(), {'longstruct': st1}, format='5',long_field_names=True) + + +def test_long_field_names_in_struct(): + # Regression test - long_field_names was erased if you passed a struct + # within a struct + lim = 63 + fldname = 'a' * lim + cell = np.ndarray((1,2),dtype=object) + st1 = np.zeros((1,1), dtype=[(fldname, object)]) + cell[0,0]=st1 + cell[0,1]=st1 + mat_stream = StringIO() + savemat(StringIO(), {'longstruct': cell}, format='5',long_field_names=True) + # + # Check to make sure it fails with long field names off + # + assert_raises(ValueError, savemat, StringIO(), + {'longstruct': cell}, format='5', long_field_names=False) + +def test_cell_with_one_thing_in_it(): + # Regression test - make a cell array that's 1 x 2 and put two + # strings in it. It works. Make a cell array that's 1 x 1 and put + # a string in it. It should work but, in the old days, it didn't. + cells = np.ndarray((1,2),dtype=object) + cells[0,0]='Hello' + cells[0,1]='World' + mat_stream = StringIO() + savemat(StringIO(), {'x': cells}, format='5') + + cells = np.ndarray((1,1),dtype=object) + cells[0,0]='Hello, world' + mat_stream = StringIO() + savemat(StringIO(), {'x': cells}, format='5') + +def test_writer_properties(): + # Tests getting, setting of properties of matrix writer + mfw = MatFile5Writer(StringIO()) + yield assert_equal, mfw.global_vars, [] + mfw.global_vars = ['avar'] + yield assert_equal, mfw.global_vars, ['avar'] + yield assert_equal, mfw.unicode_strings, False + mfw.unicode_strings = True + yield assert_equal, mfw.unicode_strings, True + yield assert_equal, mfw.long_field_names, False + mfw.long_field_names = True + yield assert_equal, mfw.long_field_names, True From scipy-svn at scipy.org Sat Dec 13 21:59:48 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 13 Dec 2008 20:59:48 -0600 (CST) Subject: [Scipy-svn] r5247 - trunk/scipy/io/matlab/tests Message-ID: <20081214025948.C2A05C7C00E@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-13 20:59:20 -0600 (Sat, 13 Dec 2008) New Revision: 5247 Modified: trunk/scipy/io/matlab/tests/test_mio.py Log: Moderately hackey small data element writing check Modified: trunk/scipy/io/matlab/tests/test_mio.py =================================================================== --- trunk/scipy/io/matlab/tests/test_mio.py 2008-12-14 02:30:09 UTC (rev 5246) +++ trunk/scipy/io/matlab/tests/test_mio.py 2008-12-14 02:59:20 UTC (rev 5247) @@ -25,7 +25,8 @@ import scipy.sparse as SP from scipy.io.matlab.mio import loadmat, savemat, find_mat_file -from scipy.io.matlab.mio5 import MatlabObject, MatFile5Writer +from scipy.io.matlab.mio5 import MatlabObject, MatFile5Writer, \ + Mat5NumericWriter test_data_path = join(dirname(__file__), 'data') @@ -405,6 +406,7 @@ mat_stream = StringIO() savemat(StringIO(), {'x': cells}, format='5') + def test_writer_properties(): # Tests getting, setting of properties of matrix writer mfw = MatFile5Writer(StringIO()) @@ -417,3 +419,19 @@ yield assert_equal, mfw.long_field_names, False mfw.long_field_names = True yield assert_equal, mfw.long_field_names, True + + +def test_use_small_element(): + # Test whether we're using small data element or not + sio = StringIO() + # First check size for no sde for name + writer = Mat5NumericWriter(sio, np.zeros(10), 'aaaaa').write() + w_sz = sio.len + # Check small name results in largish difference in size + sio.truncate(0) + writer = Mat5NumericWriter(sio, np.zeros(10), 'aaaa').write() + yield assert_true, w_sz - sio.len > 4 + # Whereas increasing name size makes less difference + sio.truncate(0) + writer = Mat5NumericWriter(sio, np.zeros(10), 'aaaaaa').write() + yield assert_true, sio.len - w_sz < 4 From scipy-svn at scipy.org Sat Dec 13 23:20:53 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 13 Dec 2008 22:20:53 -0600 (CST) Subject: [Scipy-svn] r5248 - trunk/scipy/ndimage Message-ID: <20081214042053.100CDC7C00E@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-13 22:20:51 -0600 (Sat, 13 Dec 2008) New Revision: 5248 Modified: trunk/scipy/ndimage/filters.py Log: Added some more documentation for common optional parameters, changed default arguments from empty dictionary to None to prevent persistent changes in default Modified: trunk/scipy/ndimage/filters.py =================================================================== --- trunk/scipy/ndimage/filters.py 2008-12-14 02:59:20 UTC (rev 5247) +++ trunk/scipy/ndimage/filters.py 2008-12-14 04:20:51 UTC (rev 5248) @@ -34,23 +34,25 @@ import _nd_image _mode_doc = \ -"""The mode parameter determines how the array borders are handled, - where cval is the value when mode is equal to 'constant'. Other +"""The ``mode`` parameter determines how the array borders are handled, + where ``cval`` is the value when mode is equal to 'constant'. Other modes are 'nearest', 'mirror', 'reflect' and 'wrap'.""" -_origin_doc = """ +_origin_doc = \ +"""The ``origin`` parameter (optional) controls the placement of the filter.""" - The origin parameter controls the placement of the filter.""" +_output_doc = \ +"""The ``output`` parameter (optional) passes an array in which to store + the filter output.""" def moredoc(*args): def decorate(f): if f.__doc__ is not None: - for a in args: - f.__doc__ += a + f.__doc__ += '\n' + '\n'.join(args) return f return decorate - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def correlate1d(input, weights, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional correlation along the given axis. @@ -58,7 +60,6 @@ The lines of the array along the given axis are correlated with the given weights. The weights parameter must be a one-dimensional sequence of numbers. - """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -78,7 +79,7 @@ origin) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def convolve1d(input, weights, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional convolution along the given axis. @@ -86,7 +87,6 @@ The lines of the array along the given axis are convolved with the given weights. The weights parameter must be a one-dimensional sequence of numbers. - """ weights = weights[::-1] origin = -origin @@ -104,7 +104,6 @@ kernel. An order of 1, 2, or 3 corresponds to convolution with the first, second or third derivatives of a Gaussian. Higher order derivatives are not implemented. - """ sd = float(sigma) # make the length of the filter equal to 4 times the standard @@ -147,7 +146,7 @@ weights[lw - ii] = tmp return correlate1d(input, weights, axis, output, mode, cval, 0) - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def gaussian_filter(input, sigma, order = 0, output = None, mode = "reflect", cval = 0.0): """Multi-dimensional Gaussian filter. @@ -167,7 +166,6 @@ types with a limited precision, the results may be imprecise because intermediate results may be stored with insufficient precision. - """ input = numpy.asarray(input) output, return_value = _ni_support._get_output(output, input) @@ -185,10 +183,9 @@ output[...] = input[...] return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def prewitt(input, axis = -1, output = None, mode = "reflect", cval = 0.0): """Calculate a Prewitt filter. - """ input = numpy.asarray(input) axis = _ni_support._check_axis(axis, input.ndim) @@ -199,10 +196,9 @@ correlate1d(output, [1, 1, 1], ii, output, mode, cval, 0,) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def sobel(input, axis = -1, output = None, mode = "reflect", cval = 0.0): """Calculate a Sobel filter. - """ input = numpy.asarray(input) axis = _ni_support._check_axis(axis, input.ndim) @@ -213,9 +209,11 @@ correlate1d(output, [1, 2, 1], ii, output, mode, cval, 0) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def generic_laplace(input, derivative2, output = None, mode = "reflect", - cval = 0.0, extra_arguments = (), extra_keywords = {}): + cval = 0.0, + extra_arguments = (), + extra_keywords = None): """Calculate a multidimensional laplace filter using the provided second derivative function. @@ -228,8 +226,9 @@ The extra_arguments and extra_keywords arguments can be used to pass extra arguments and keywords that are passed to derivative2 at each call. - """ + if extra_keywords is None: + extra_keywords = {} input = numpy.asarray(input) output, return_value = _ni_support._get_output(output, input) axes = range(input.ndim) @@ -244,17 +243,16 @@ output[...] = input[...] return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def laplace(input, output = None, mode = "reflect", cval = 0.0): """Calculate a multidimensional laplace filter using an estimation for the second derivative based on differences. - """ def derivative2(input, axis, output, mode, cval): return correlate1d(input, [1, -2, 1], axis, output, mode, cval, 0) return generic_laplace(input, derivative2, output, mode, cval) - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def gaussian_laplace(input, sigma, output = None, mode = "reflect", cval = 0.0): """Calculate a multidimensional laplace filter using gaussian @@ -263,7 +261,6 @@ The standard-deviations of the Gaussian filter are given for each axis as a sequence, or as a single number, in which case it is equal for all axes.. - """ input = numpy.asarray(input) def derivative2(input, axis, output, mode, cval, sigma): @@ -273,24 +270,30 @@ return generic_laplace(input, derivative2, output, mode, cval, extra_arguments = (sigma,)) - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def generic_gradient_magnitude(input, derivative, output = None, mode = "reflect", cval = 0.0, - extra_arguments = (), extra_keywords = {}): - """Calculate a gradient magnitude using the provdide function for + extra_arguments = (), extra_keywords = None): + """Calculate a gradient magnitude using the provided function for the gradient. The derivative parameter must be a callable with the following - signature: + signature:: - derivative(input, axis, output, mode, cval, - *extra_arguments, **extra_keywords) + derivative(input, axis, output, mode, cval, + *extra_arguments, **extra_keywords) + ``derivative`` can assume that ``input`` and ``output`` are ndarrays. + + Note that the output from ``derivative`` is modified inplace; be + careful to copy important inputs before returning them. + The extra_arguments and extra_keywords arguments can be used to pass - extra arguments and keywords that are passed to derivative2 at each + extra arguments and keywords that are passed to ``derivative`` at each call. - """ + if extra_keywords is None: + extra_keywords = {} input = numpy.asarray(input) output, return_value = _ni_support._get_output(output, input) axes = range(input.ndim) @@ -308,7 +311,7 @@ output[...] = input[...] return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def gaussian_gradient_magnitude(input, sigma, output = None, mode = "reflect", cval = 0.0): """Calculate a multidimensional gradient magnitude using gaussian @@ -317,7 +320,6 @@ The standard-deviations of the Gaussian filter are given for each axis as a sequence, or as a single number, in which case it is equal for all axes.. - """ input = numpy.asarray(input) def derivative(input, axis, output, mode, cval, sigma): @@ -353,36 +355,33 @@ _nd_image.correlate(input, weights, output, mode, cval, origins) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def correlate(input, weights, output = None, mode = 'reflect', cval = 0.0, origin = 0): """Multi-dimensional correlation. The array is correlated with the given kernel. - """ return _correlate_or_convolve(input, weights, output, mode, cval, origin, False) - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def convolve(input, weights, output = None, mode = 'reflect', cval = 0.0, origin = 0): """Multi-dimensional convolution. The array is convolved with the given kernel. - """ return _correlate_or_convolve(input, weights, output, mode, cval, origin, True) - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def uniform_filter1d(input, size, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional uniform filter along the given axis. The lines of the array along the given axis are filtered with a uniform filter of given size. - """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -398,7 +397,7 @@ origin) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def uniform_filter(input, size = 3, output = None, mode = "reflect", cval = 0.0, origin = 0): """Multi-dimensional uniform filter. @@ -412,7 +411,6 @@ in the same data type as the output. Therefore, for output types with a limited precision, the results may be imprecise because intermediate results may be stored with insufficient precision. - """ input = numpy.asarray(input) output, return_value = _ni_support._get_output(output, input) @@ -430,14 +428,13 @@ output[...] = input[...] return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def minimum_filter1d(input, size, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional minimum filter along the given axis. The lines of the array along the given axis are filtered with a minimum filter of given size. - """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -453,14 +450,13 @@ origin, 1) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def maximum_filter1d(input, size, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional maximum filter along the given axis. The lines of the array along the given axis are filtered with a maximum filter of given size. - """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -539,31 +535,29 @@ mode, cval, origins, minimum) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def minimum_filter(input, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional minimum filter. Either a size or a footprint with the filter must be provided. An output array can optionally be provided. - """ return _min_or_max_filter(input, size, footprint, None, output, mode, cval, origin, 1) - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def maximum_filter(input, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional maximum filter. Either a size or a footprint with the filter must be provided. An output array can optionally be provided. - """ return _min_or_max_filter(input, size, footprint, None, output, mode, cval, origin, 0) - + at moredoc(_mode_doc, _origin_doc, _output_doc) def _rank_filter(input, rank, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0, operation = 'rank'): input = numpy.asarray(input) @@ -615,7 +609,7 @@ origins) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def rank_filter(input, rank, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional rank filter. @@ -624,24 +618,22 @@ indicates the larges element. Either a size or a footprint with the filter must be provided. An output array can optionally be provided. - """ return _rank_filter(input, rank, size, footprint, output, mode, cval, origin, 'rank') - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def median_filter(input, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional median filter. Either a size or a footprint with the filter must be provided. An output array can optionally be provided. - """ return _rank_filter(input, 0, size, footprint, output, mode, cval, origin, 'median') - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def percentile_filter(input, percentile, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional percentile filter. @@ -650,12 +642,11 @@ -20 equals percentile = 80. Either a size or a footprint with the filter must be provided. An output array can optionally be provided. - """ return _rank_filter(input, percentile, size, footprint, output, mode, cval, origin, 'percentile') - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def generic_filter1d(input, function, filter_size, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0, extra_arguments = (), extra_keywords = {}): @@ -664,12 +655,11 @@ The function iterates over the lines of the array, calling the given function at each line. The arguments of the line are the input line, and the output line. The input and output lines are 1D - double arrays. The input line is extended appropiately according + double arrays. The input line is extended appropriately according to the filter size and origin. The output line must be modified in-place with the result. The extra_arguments and extra_keywords arguments can be used to pass extra arguments and keywords that are passed to the function at each call. - """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -686,10 +676,10 @@ mode, cval, origin, extra_arguments, extra_keywords) return return_value - at moredoc(_mode_doc, _origin_doc) + at moredoc(_mode_doc, _origin_doc, _output_doc) def generic_filter(input, function, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0, - extra_arguments = (), extra_keywords = {}): + extra_arguments = (), extra_keywords = None): """Calculates a multi-dimensional filter using the given function. At each element the provided function is called. The input values @@ -700,8 +690,9 @@ output array can optionally be provided. The extra_arguments and extra_keywords arguments can be used to pass extra arguments and keywords that are passed to the function at each call. - """ + if extra_keywords is None: + extra_keywords = {} input = numpy.asarray(input) if numpy.iscomplexobj(input): raise TypeError, 'Complex type not supported' From scipy-svn at scipy.org Sun Dec 14 04:41:10 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 03:41:10 -0600 (CST) Subject: [Scipy-svn] r5249 - trunk/doc/release Message-ID: <20081214094110.C9D5EC7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-14 03:41:08 -0600 (Sun, 14 Dec 2008) New Revision: 5249 Modified: trunk/doc/release/0.7.0-notes.rst Log: add release notes for RBF and constants Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-14 04:20:51 UTC (rev 5248) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-14 09:41:08 UTC (rev 5249) @@ -129,12 +129,24 @@ New Constants package ~~~~~~~~~~~~~~~~~~~~~ -Collection of physical constants and conversion factors. +``scipy.constants`` provides a collection of physical constants and +conversion factors. These constants are taken from CODATA Recommended +Values of the Fundamental Physical Constants: 2002. They may be found +at physics.nist.gov/constants. The values are stored in the dictionary +physical_constants as a tuple containing the value, the units, and +the relative precision, in that order. All constants are in SI units +unless otherwise stated. Several helper functions are provided. +The list is not meant to be comprehensive, but just a convenient list +for everyday use. + New Radial Basis Function module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -http://scipy.org/scipy/scipy/browser/trunk/scipy/interpolate/rbf.py +``scipy.interpolate`` now contains a Radial Basis Function module. +Radial basis functions can be used for smoothing/interpolating scattered +data in n-dimensions, but should be used with caution for extrapolation +outside of the observed data range. New complex ODE integrator ~~~~~~~~~~~~~~~~~~~~~~~~~~ From scipy-svn at scipy.org Sun Dec 14 05:05:58 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 04:05:58 -0600 (CST) Subject: [Scipy-svn] r5250 - trunk/doc/release Message-ID: <20081214100558.92EE6C7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-14 04:05:51 -0600 (Sun, 14 Dec 2008) New Revision: 5250 Modified: trunk/doc/release/0.7.0-notes.rst Log: improved testing framework release notes Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-14 09:41:08 UTC (rev 5249) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-14 10:05:51 UTC (rev 5250) @@ -220,9 +220,19 @@ Running Tests ~~~~~~~~~~~~~ -We are moving away from having our own testing framework and are -adopting `nose `__. +NumPy 1.2 introduced a new testing framework based on `nose +`__. Starting with this release SciPy now +uses the new NumPy test framework as well. To take advantage of the new testing framework +requires nose version 0.10 or later. One major advantage of the new framework is that +it greatly reduces the difficulty of writing unit tests, which has all ready paid off given +the rapid increase in tests. To run the full test suite:: + >>> import scipy + >>> scipy.test('full') + +For more information, please see `The NumPy/SciPy Testing Guide +`__. + Building SciPy ~~~~~~~~~~~~~~ From scipy-svn at scipy.org Sun Dec 14 06:21:12 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 05:21:12 -0600 (CST) Subject: [Scipy-svn] r5251 - trunk/doc/source/tutorial Message-ID: <20081214112112.B8DEBC7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-14 05:21:11 -0600 (Sun, 14 Dec 2008) New Revision: 5251 Modified: trunk/doc/source/tutorial/interpolate.rst Log: fixed rest Modified: trunk/doc/source/tutorial/interpolate.rst =================================================================== --- trunk/doc/source/tutorial/interpolate.rst 2008-12-14 10:05:51 UTC (rev 5250) +++ trunk/doc/source/tutorial/interpolate.rst 2008-12-14 11:21:11 UTC (rev 5251) @@ -199,7 +199,7 @@ :obj:`ogrid ` command if the full-mesh is not needed). The number of output arguments and the number of dimensions of each argument is determined by the number of indexing objects -passed in :obj:`mgrid `[]. +passed in :obj:`mgrid `. .. plot:: From scipy-svn at scipy.org Sun Dec 14 06:51:27 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 05:51:27 -0600 (CST) Subject: [Scipy-svn] r5252 - trunk/doc/source/tutorial Message-ID: <20081214115127.7C07AC7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-14 05:51:25 -0600 (Sun, 14 Dec 2008) New Revision: 5252 Modified: trunk/doc/source/tutorial/interpolate.rst Log: remove * import Modified: trunk/doc/source/tutorial/interpolate.rst =================================================================== --- trunk/doc/source/tutorial/interpolate.rst 2008-12-14 11:21:11 UTC (rev 5251) +++ trunk/doc/source/tutorial/interpolate.rst 2008-12-14 11:51:25 UTC (rev 5252) @@ -28,14 +28,14 @@ .. plot:: - >>> from numpy import * + >>> import numpy as np >>> from scipy import interpolate - >>> x = arange(0,10) - >>> y = exp(-x/3.0) + >>> x = np.arange(0,10) + >>> y = np.exp(-x/3.0) >>> f = interpolate.interp1d(x, y) - >>> xnew = arange(0,9,0.1) + >>> xnew = np.arange(0,9,0.1) >>> import matplotlib.pyplot as plt >>> plt.plot(x,y,'o',xnew,f(xnew),'-') @@ -91,20 +91,20 @@ .. plot:: - >>> from numpy import * + >>> import numpy as np >>> import matplotlib.pyplot as plt >>> from scipy import interpolate Cubic-spline - >>> x = arange(0,2*pi+pi/4,2*pi/8) - >>> y = sin(x) + >>> x = np.arange(0,2*np.pi+np.pi/4,2*np.pi/8) + >>> y = np.sin(x) >>> tck = interpolate.splrep(x,y,s=0) - >>> xnew = arange(0,2*pi,pi/50) + >>> xnew = np.arange(0,2*np.pi,np.pi/50) >>> ynew = interpolate.splev(xnew,tck,der=0) >>> plt.figure() - >>> plt.plot(x,y,'x',xnew,ynew,xnew,sin(xnew),x,y,'b') + >>> plt.plot(x,y,'x',xnew,ynew,xnew,np.sin(xnew),x,y,'b') >>> plt.legend(['Linear','Cubic Spline', 'True']) >>> plt.axis([-0.05,6.33,-1.05,1.05]) >>> plt.title('Cubic-spline interpolation') @@ -114,7 +114,7 @@ >>> yder = interpolate.splev(xnew,tck,der=1) >>> plt.figure() - >>> plt.plot(xnew,yder,xnew,cos(xnew),'--') + >>> plt.plot(xnew,yder,xnew,np.cos(xnew),'--') >>> plt.legend(['Cubic Spline', 'True']) >>> plt.axis([-0.05,6.33,-1.05,1.05]) >>> plt.title('Derivative estimation from spline') @@ -123,8 +123,8 @@ Integral of spline >>> def integ(x,tck,constant=-1): - >>> x = atleast_1d(x) - >>> out = zeros(x.shape, dtype=x.dtype) + >>> x = np.atleast_1d(x) + >>> out = np.zeros(x.shape, dtype=x.dtype) >>> for n in xrange(len(out)): >>> out[n] = interpolate.splint(0,x[n],tck) >>> out += constant @@ -132,7 +132,7 @@ >>> >>> yint = integ(xnew,tck) >>> plt.figure() - >>> plt.plot(xnew,yint,xnew,-cos(xnew),'--') + >>> plt.plot(xnew,yint,xnew,-np.cos(xnew),'--') >>> plt.legend(['Cubic Spline', 'True']) >>> plt.axis([-0.05,6.33,-1.05,1.05]) >>> plt.title('Integral estimation from spline') @@ -145,14 +145,14 @@ Parametric spline - >>> t = arange(0,1.1,.1) - >>> x = sin(2*pi*t) - >>> y = cos(2*pi*t) + >>> t = np.arange(0,1.1,.1) + >>> x = np.sin(2*np.pi*t) + >>> y = np.cos(2*np.pi*t) >>> tck,u = interpolate.splprep([x,y],s=0) - >>> unew = arange(0,1.01,0.01) + >>> unew = np.arange(0,1.01,0.01) >>> out = interpolate.splev(unew,tck) >>> plt.figure() - >>> plt.plot(x,y,'x',out[0],out[1],sin(2*pi*unew),cos(2*pi*unew),x,y,'b') + >>> plt.plot(x,y,'x',out[0],out[1],np.sin(2*np.pi*unew),np.cos(2*np.pi*unew),x,y,'b') >>> plt.legend(['Linear','Cubic Spline', 'True']) >>> plt.axis([-1.05,1.05,-1.05,1.05]) >>> plt.title('Spline of parametrically-defined curve') @@ -203,14 +203,14 @@ .. plot:: - >>> from numpy import * + >>> import numpy as np >>> from scipy import interpolate >>> import matplotlib.pyplot as plt Define function over sparse 20x20 grid - >>> x,y = mgrid[-1:1:20j,-1:1:20j] - >>> z = (x+y)*exp(-6.0*(x*x+y*y)) + >>> x,y = np.mgrid[-1:1:20j,-1:1:20j] + >>> z = (x+y)*np.exp(-6.0*(x*x+y*y)) >>> plt.figure() >>> plt.pcolor(x,y,z) @@ -220,7 +220,7 @@ Interpolate function over new 70x70 grid - >>> xnew,ynew = mgrid[-1:1:70j,-1:1:70j] + >>> xnew,ynew = np.mgrid[-1:1:70j,-1:1:70j] >>> tck = interpolate.bisplrep(x,y,z,s=0) >>> znew = interpolate.bisplev(xnew[:,0],ynew[0,:],tck) From scipy-svn at scipy.org Sun Dec 14 06:51:41 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 05:51:41 -0600 (CST) Subject: [Scipy-svn] r5253 - in trunk/scipy/ndimage: . tests Message-ID: <20081214115141.6EFF8C7C00E@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-14 05:51:37 -0600 (Sun, 14 Dec 2008) New Revision: 5253 Added: trunk/scipy/ndimage/doccer.py trunk/scipy/ndimage/tests/test_doccer.py trunk/scipy/ndimage/tests/test_filters.py Modified: trunk/scipy/ndimage/filters.py Log: Refactored documentation for parameters, added regression test for ticket 701 Added: trunk/scipy/ndimage/doccer.py =================================================================== --- trunk/scipy/ndimage/doccer.py 2008-12-14 11:51:25 UTC (rev 5252) +++ trunk/scipy/ndimage/doccer.py 2008-12-14 11:51:37 UTC (rev 5253) @@ -0,0 +1,37 @@ +import sys + +def docformat(docstring, docdict=None): + ''' Fill a function docstring from variables in dict + + Adapt the indent of the inserted docs + ''' + if not docstring: + return docstring + if docdict is None: + docdict = {} + lines = docstring.expandtabs().splitlines() + # Find the minimum indent of the main docstring, after last line + indentno = sys.maxint + for line in lines[1:]: + stripped = line.lstrip() + if stripped: + indentno = min(indentno, len(line) - len(stripped)) + indent = ' ' * indentno + # Insert this indent to dictionary docstrings + indented = {} + for name, dstr in docdict.items(): + lines = dstr.expandtabs().splitlines() + newlines = [lines[0]] + for line in lines[1:]: + newlines.append(indent+line) + indented[name] = '\n'.join(newlines) + return docstring % indented + + +def filldoc(docdict): + ''' Return docstring decorator using docdict variable dictionary''' + def decorate(f): + f.__doc__ = docformat(f.__doc__, docdict) + return f + return decorate + Modified: trunk/scipy/ndimage/filters.py =================================================================== --- trunk/scipy/ndimage/filters.py 2008-12-14 11:51:25 UTC (rev 5252) +++ trunk/scipy/ndimage/filters.py 2008-12-14 11:51:37 UTC (rev 5253) @@ -32,34 +32,87 @@ import numpy import _ni_support import _nd_image +import doccer +_input_doc = \ +"""input : array-like + input array to filter""" +_axis_doc = \ +"""axis : integer, optional + axis of ``input`` along which to calculate. Default is -1""" +_output_doc = \ +"""output : array, optional + The ``output`` parameter passes an array in which to store the + filter output.""" +_size_foot_doc = \ +"""size : scalar or tuple, optional + See footprint, below +footprint : array, optional + Either ``size`` or ``footprint`` must be defined. ``size`` gives + the shape that is taken from the input array, at every element + position, to define the input to the filter function. + ``footprint`` is a boolean array that specifies (implicitly) a + shape, but also which of the elements within this shape will get + passed to the filter function. Thus ``size=(n,m)`` is equivalent + to ``footprint=np.ones((n,m))``. We adjust ``size`` to the number + of dimensions of the input array, so that, if the input array is + shape (10,10,10), and ``size`` is 2, then the actual size used is + (2,2,2). +""" _mode_doc = \ -"""The ``mode`` parameter determines how the array borders are handled, - where ``cval`` is the value when mode is equal to 'constant'. Other - modes are 'nearest', 'mirror', 'reflect' and 'wrap'.""" - +"""mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional + The ``mode`` parameter determines how the array borders are + handled, where ``cval`` is the value when mode is equal to + 'constant'. Default is 'reflect'""" +_cval_doc = \ +"""cval : scalar, optional + Value to fill past edges of input if ``mode`` is 'constant'. Default + is 0.0""" _origin_doc = \ -"""The ``origin`` parameter (optional) controls the placement of the filter.""" +"""origin : scalar, optional +The ``origin`` parameter controls the placement of the filter. Default 0""" +_extra_arguments_doc = \ +"""extra_arguments : sequence + Sequence of extra positional arguments to pass to passed function""" +_extra_arguments_doc = \ +"""extra_arguments : sequence, optional + Sequence of extra positional arguments to pass to passed function""" +_extra_keywords_doc = \ +"""extra_keywords : dict, optional + dict of extra keyword arguments to pass to passed function""" -_output_doc = \ -"""The ``output`` parameter (optional) passes an array in which to store - the filter output.""" +docdict = { + 'input':_input_doc, + 'axis':_axis_doc, + 'output':_output_doc, + 'size_foot':_size_foot_doc, + 'mode':_mode_doc, + 'cval':_cval_doc, + 'origin':_origin_doc, + 'extra_arguments':_extra_arguments_doc, + 'extra_keywords':_extra_keywords_doc, + } + +docfiller = doccer.filldoc(docdict) -def moredoc(*args): - def decorate(f): - if f.__doc__ is not None: - f.__doc__ += '\n' + '\n'.join(args) - return f - return decorate - - at moredoc(_mode_doc, _origin_doc, _output_doc) + at docfiller def correlate1d(input, weights, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional correlation along the given axis. The lines of the array along the given axis are correlated with the - given weights. The weights parameter must be a one-dimensional sequence - of numbers. + given weights. + + Parameters + ---------- + %(input)s + weights : array + one-dimensional sequence of numbers + %(axis)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -79,14 +132,25 @@ origin) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def convolve1d(input, weights, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional convolution along the given axis. The lines of the array along the given axis are convolved with the - given weights. The weights parameter must be a one-dimensional sequence - of numbers. + given weights. + + Parameters + ---------- + %(input)s + weights : ndarray + one-dimensional sequence of numbers + %(axis)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ weights = weights[::-1] origin = -origin @@ -94,16 +158,26 @@ origin -= 1 return correlate1d(input, weights, axis, output, mode, cval, origin) - at moredoc(_mode_doc, _origin_doc) + + at docfiller def gaussian_filter1d(input, sigma, axis = -1, order = 0, output = None, mode = "reflect", cval = 0.0): """One-dimensional Gaussian filter. - The standard-deviation of the Gaussian filter is given by - sigma. An order of 0 corresponds to convolution with a Gaussian - kernel. An order of 1, 2, or 3 corresponds to convolution with the - first, second or third derivatives of a Gaussian. Higher order - derivatives are not implemented. + Parameters + ---------- + %(input)s + sigma : scalar + standard deviation for Gaussian kernel + %(axis)s + order : {0, 1, 2, 3}, optional + An order of 0 corresponds to convolution with a Gaussian + kernel. An order of 1, 2, or 3 corresponds to convolution with + the first, second or third derivatives of a Gaussian. Higher + order derivatives are not implemented + %(output)s + %(mode)s + %(cval)s """ sd = float(sigma) # make the length of the filter equal to 4 times the standard @@ -146,21 +220,34 @@ weights[lw - ii] = tmp return correlate1d(input, weights, axis, output, mode, cval, 0) - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def gaussian_filter(input, sigma, order = 0, output = None, mode = "reflect", cval = 0.0): """Multi-dimensional Gaussian filter. - The standard-deviations of the Gaussian filter are given for each - axis as a sequence, or as a single number, in which case it is - equal for all axes. The order of the filter along each axis is - given as a sequence of integers, or as a single number. An order - of 0 corresponds to convolution with a Gaussian kernel. An order - of 1, 2, or 3 corresponds to convolution with the first, second or - third derivatives of a Gaussian. Higher order derivatives are not - implemented.' + Parameters + ---------- + %(input)s + sigma : scalar or sequence of scalars + standard deviation for Gaussian kernel. The standard + deviations of the Gaussian filter are given for each axis as a + sequence, or as a single number, in which case it is equal for + all axes. + order : {0, 1, 2, 3} or sequence from same set, optional + The order of the filter along each axis is given as a sequence + of integers, or as a single number. An order of 0 corresponds + to convolution with a Gaussian kernel. An order of 1, 2, or 3 + corresponds to convolution with the first, second or third + derivatives of a Gaussian. Higher order derivatives are not + implemented + %(output)s + %(mode)s + %(cval)s - Note: The multi-dimensional filter is implemented as a sequence of + Notes + ----- + The multi-dimensional filter is implemented as a sequence of one-dimensional convolution filters. The intermediate arrays are stored in the same data type as the output. Therefore, for output types with a limited precision, the results may be imprecise @@ -183,9 +270,18 @@ output[...] = input[...] return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def prewitt(input, axis = -1, output = None, mode = "reflect", cval = 0.0): """Calculate a Prewitt filter. + + Parameters + ---------- + %(input)s + %(axis)s + %(output)s + %(mode)s + %(cval)s """ input = numpy.asarray(input) axis = _ni_support._check_axis(axis, input.ndim) @@ -196,9 +292,18 @@ correlate1d(output, [1, 1, 1], ii, output, mode, cval, 0,) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def sobel(input, axis = -1, output = None, mode = "reflect", cval = 0.0): """Calculate a Sobel filter. + + Parameters + ---------- + %(input)s + %(axis)s + %(output)s + %(mode)s + %(cval)s """ input = numpy.asarray(input) axis = _ni_support._check_axis(axis, input.ndim) @@ -209,7 +314,8 @@ correlate1d(output, [1, 2, 1], ii, output, mode, cval, 0) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def generic_laplace(input, derivative2, output = None, mode = "reflect", cval = 0.0, extra_arguments = (), @@ -217,15 +323,19 @@ """Calculate a multidimensional laplace filter using the provided second derivative function. - The derivative2 parameter must be a callable with the following - signature: - - derivative2(input, axis, output, mode, cval, - *extra_arguments, **extra_keywords) - - The extra_arguments and extra_keywords arguments can be used to pass - extra arguments and keywords that are passed to derivative2 at each - call. + Parameters + ---------- + %(input)s + derivative2 : callable + Callable with the following signature:: + derivative2(input, axis, output, mode, cval, + *extra_arguments, **extra_keywords) + See ``extra_arguments``, ``extra_keywords`` below + %(output)s + %(mode)s + %(cval)s + %(extra_keywords)s + %(extra_arguments)s """ if extra_keywords is None: extra_keywords = {} @@ -243,24 +353,40 @@ output[...] = input[...] return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def laplace(input, output = None, mode = "reflect", cval = 0.0): """Calculate a multidimensional laplace filter using an estimation for the second derivative based on differences. + + Parameters + ---------- + %(input)s + %(output)s + %(mode)s + %(cval)s """ def derivative2(input, axis, output, mode, cval): return correlate1d(input, [1, -2, 1], axis, output, mode, cval, 0) return generic_laplace(input, derivative2, output, mode, cval) - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def gaussian_laplace(input, sigma, output = None, mode = "reflect", cval = 0.0): """Calculate a multidimensional laplace filter using gaussian second derivatives. - The standard-deviations of the Gaussian filter are given for each - axis as a sequence, or as a single number, in which case it is - equal for all axes.. + Parameters + ---------- + %(input)s + sigma : scalar or sequence of scalars + The standard deviations of the Gaussian filter are given for + each axis as a sequence, or as a single number, in which case + it is equal for all axes.. + %(output)s + %(mode)s + %(cval)s """ input = numpy.asarray(input) def derivative2(input, axis, output, mode, cval, sigma): @@ -270,27 +396,31 @@ return generic_laplace(input, derivative2, output, mode, cval, extra_arguments = (sigma,)) - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def generic_gradient_magnitude(input, derivative, output = None, mode = "reflect", cval = 0.0, extra_arguments = (), extra_keywords = None): """Calculate a gradient magnitude using the provided function for the gradient. - The derivative parameter must be a callable with the following - signature:: - - derivative(input, axis, output, mode, cval, - *extra_arguments, **extra_keywords) - - ``derivative`` can assume that ``input`` and ``output`` are ndarrays. - - Note that the output from ``derivative`` is modified inplace; be - careful to copy important inputs before returning them. - - The extra_arguments and extra_keywords arguments can be used to pass - extra arguments and keywords that are passed to ``derivative`` at each - call. + Parameters + ---------- + %(input)s + derivative : callable + Callable with the following signature:: + derivative(input, axis, output, mode, cval, + *extra_arguments, **extra_keywords) + See ``extra_arguments``, ``extra_keywords`` below + ``derivative`` can assume that ``input`` and ``output`` are + ndarrays. + Note that the output from ``derivative`` is modified inplace; + be careful to copy important inputs before returning them. + %(output)s + %(mode)s + %(cval)s + %(extra_keywords)s + %(extra_arguments)s """ if extra_keywords is None: extra_keywords = {} @@ -311,15 +441,23 @@ output[...] = input[...] return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def gaussian_gradient_magnitude(input, sigma, output = None, mode = "reflect", cval = 0.0): """Calculate a multidimensional gradient magnitude using gaussian derivatives. - The standard-deviations of the Gaussian filter are given for each - axis as a sequence, or as a single number, in which case it is - equal for all axes.. + Parameters + ---------- + %(input)s + sigma : scalar or sequence of scalars + The standard deviations of the Gaussian filter are given for + each axis as a sequence, or as a single number, in which case + it is equal for all axes.. + %(output)s + %(mode)s + %(cval)s """ input = numpy.asarray(input) def derivative(input, axis, output, mode, cval, sigma): @@ -329,6 +467,7 @@ return generic_gradient_magnitude(input, derivative, output, mode, cval, extra_arguments = (sigma,)) + def _correlate_or_convolve(input, weights, output, mode, cval, origin, convolution): input = numpy.asarray(input) @@ -355,33 +494,67 @@ _nd_image.correlate(input, weights, output, mode, cval, origins) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def correlate(input, weights, output = None, mode = 'reflect', cval = 0.0, origin = 0): """Multi-dimensional correlation. The array is correlated with the given kernel. + + Parameters + ---------- + %(input)s + weights : ndarray + array of weights, same number of dimensions as input + %(output)s + %(mode)s + %(cval)s + %(origin)s """ return _correlate_or_convolve(input, weights, output, mode, cval, origin, False) - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def convolve(input, weights, output = None, mode = 'reflect', cval = 0.0, origin = 0): """Multi-dimensional convolution. The array is convolved with the given kernel. + + Parameters + ---------- + %(input)s + weights : ndarray + array of weights, same number of dimensions as input + %(output)s + %(mode)s + %(cval)s + %(origin)s """ return _correlate_or_convolve(input, weights, output, mode, cval, origin, True) - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def uniform_filter1d(input, size, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional uniform filter along the given axis. The lines of the array along the given axis are filtered with a uniform filter of given size. + + Parameters + ---------- + %(input)s + size : integer + length of uniform filter + %(axis)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -397,15 +570,26 @@ origin) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def uniform_filter(input, size = 3, output = None, mode = "reflect", cval = 0.0, origin = 0): """Multi-dimensional uniform filter. - The sizes of the uniform filter are given for each axis as a - sequence, or as a single number, in which case the size is equal - for all axes. + Parameters + ---------- + %(input)s + size : int or sequence of ints + The sizes of the uniform filter are given for each axis as a + sequence, or as a single number, in which case the size is + equal for all axes. + %(output)s + %(mode)s + %(cval)s + %(origin)s + Notes + ----- The multi-dimensional filter is implemented as a sequence of one-dimensional uniform filters. The intermediate arrays are stored in the same data type as the output. Therefore, for output types @@ -428,13 +612,25 @@ output[...] = input[...] return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def minimum_filter1d(input, size, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional minimum filter along the given axis. The lines of the array along the given axis are filtered with a minimum filter of given size. + + Parameters + ---------- + %(input)s + size : int + length along which to calculate 1D minimum + %(axis)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -450,13 +646,25 @@ origin, 1) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def maximum_filter1d(input, size, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculate a one-dimensional maximum filter along the given axis. The lines of the array along the given axis are filtered with a maximum filter of given size. + + Parameters + ---------- + %(input)s + size : int + length along which to calculate 1D maximum + %(axis)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ input = numpy.asarray(input) if numpy.iscomplexobj(input): @@ -472,6 +680,7 @@ origin, 0) return return_value + def _min_or_max_filter(input, size, footprint, structure, output, mode, cval, origin, minimum): if structure is None: @@ -535,29 +744,44 @@ mode, cval, origins, minimum) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def minimum_filter(input, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional minimum filter. - Either a size or a footprint with the filter must be - provided. An output array can optionally be provided. + Parameters + ---------- + %(input)s + %(size_foot)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ return _min_or_max_filter(input, size, footprint, None, output, mode, cval, origin, 1) - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def maximum_filter(input, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional maximum filter. - Either a size or a footprint with the filter must be - provided. An output array can optionally be provided. + Parameters + ---------- + %(input)s + %(size_foot)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ return _min_or_max_filter(input, size, footprint, None, output, mode, cval, origin, 0) - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def _rank_filter(input, rank, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0, operation = 'rank'): input = numpy.asarray(input) @@ -609,58 +833,97 @@ origins) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def rank_filter(input, rank, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional rank filter. - The rank parameter may be less then zero, i.e., rank = -1 - indicates the larges element. Either a size or a footprint with - the filter must be provided. An output array can optionally be - provided. + Parameters + ---------- + %(input)s + rank : integer + The rank parameter may be less then zero, i.e., rank = -1 + indicates the largest element. + %(size_foot)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ return _rank_filter(input, rank, size, footprint, output, mode, cval, origin, 'rank') - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def median_filter(input, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional median filter. - Either a size or a footprint with the filter must be provided. An - output array can optionally be provided. + Parameters + ---------- + %(input)s + %(size_foot)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ return _rank_filter(input, 0, size, footprint, output, mode, cval, origin, 'median') - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def percentile_filter(input, percentile, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0): """Calculates a multi-dimensional percentile filter. - The percentile parameter may be less then zero, i.e., percentile = - -20 equals percentile = 80. Either a size or a footprint with the - filter must be provided. An output array can optionally be - provided. + Parameters + ---------- + %(input)s + percentile : scalar + The percentile parameter may be less then zero, i.e., + percentile = -20 equals percentile = 80 + %(size_foot)s + %(output)s + %(mode)s + %(cval)s + %(origin)s """ return _rank_filter(input, percentile, size, footprint, output, mode, cval, origin, 'percentile') - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def generic_filter1d(input, function, filter_size, axis = -1, output = None, mode = "reflect", cval = 0.0, origin = 0, - extra_arguments = (), extra_keywords = {}): + extra_arguments = (), extra_keywords = None): """Calculate a one-dimensional filter along the given axis. - The function iterates over the lines of the array, calling the + generic_filter1d iterates over the lines of the array, calling the given function at each line. The arguments of the line are the input line, and the output line. The input and output lines are 1D double arrays. The input line is extended appropriately according to the filter size and origin. The output line must be modified - in-place with the result. The extra_arguments and extra_keywords - arguments can be used to pass extra arguments and keywords that - are passed to the function at each call. + in-place with the result. + + Parameters + ---------- + %(input)s + function : callable + function to apply along given axis + filter_size : scalar + length of the filter + %(axis)s + %(output)s + %(mode)s + %(cval)s + %(origin)s + %(extra_arguments)s + %(extra_keywords)s """ + if extra_keywords is None: + extra_keywords = {} input = numpy.asarray(input) if numpy.iscomplexobj(input): raise TypeError, 'Complex type not supported' @@ -676,7 +939,8 @@ mode, cval, origin, extra_arguments, extra_keywords) return return_value - at moredoc(_mode_doc, _origin_doc, _output_doc) + + at docfiller def generic_filter(input, function, size = None, footprint = None, output = None, mode = "reflect", cval = 0.0, origin = 0, extra_arguments = (), extra_keywords = None): @@ -686,10 +950,18 @@ within the filter footprint at that element are passed to the function as a 1D array of double values. - Either a size or a footprint with the filter must be provided. An - output array can optionally be provided. The extra_arguments and - extra_keywords arguments can be used to pass extra arguments and - keywords that are passed to the function at each call. + Parameters + ---------- + %(input)s + function : callable + function to apply at each element + %(size_foot)s + %(output)s + %(mode)s + %(cval)s + %(origin)s + %(extra_arguments)s + %(extra_keywords)s """ if extra_keywords is None: extra_keywords = {} Added: trunk/scipy/ndimage/tests/test_doccer.py =================================================================== --- trunk/scipy/ndimage/tests/test_doccer.py 2008-12-14 11:51:25 UTC (rev 5252) +++ trunk/scipy/ndimage/tests/test_doccer.py 2008-12-14 11:51:37 UTC (rev 5253) @@ -0,0 +1,25 @@ +''' Some tests for the documenting decorator ''' + +import numpy as np + +from numpy.testing import assert_equal, assert_raises + +from nose.tools import assert_true + +from scipy.ndimage.doccer import docformat, filldoc + +def test_docformat(): + docstring = \ + """Docstring + %(strtest)s + """ + param_doc = \ +"""Another test + with some indent""" + formatted = docformat(docstring, {'strtest':param_doc}) + expected = \ +"""Docstring + Another test + with some indent + """ + assert_equal(formatted, expected) Added: trunk/scipy/ndimage/tests/test_filters.py =================================================================== --- trunk/scipy/ndimage/tests/test_filters.py 2008-12-14 11:51:25 UTC (rev 5252) +++ trunk/scipy/ndimage/tests/test_filters.py 2008-12-14 11:51:37 UTC (rev 5253) @@ -0,0 +1,18 @@ +''' Some tests for filters ''' + +import numpy as np + +from numpy.testing import assert_equal, assert_raises + +from nose.tools import assert_true + +import scipy.ndimage as sndi + +def test_ticket_701(): + # Test generic filter sizes + arr = np.arange(4).reshape((2,2)) + func = lambda x: np.min(x) + res = sndi.generic_filter(arr, func, size=(1,1)) + # The following raises an error unless ticket 701 is fixed + res2 = sndi.generic_filter(arr, func, size=1) + assert_equal(res, res2) From scipy-svn at scipy.org Sun Dec 14 07:04:39 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 06:04:39 -0600 (CST) Subject: [Scipy-svn] r5254 - trunk/scipy/ndimage Message-ID: <20081214120439.D3B86C7C00E@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-14 06:04:36 -0600 (Sun, 14 Dec 2008) New Revision: 5254 Modified: trunk/scipy/ndimage/doccer.py Log: Some more docstrings for the doc formatting module Modified: trunk/scipy/ndimage/doccer.py =================================================================== --- trunk/scipy/ndimage/doccer.py 2008-12-14 11:51:37 UTC (rev 5253) +++ trunk/scipy/ndimage/doccer.py 2008-12-14 12:04:36 UTC (rev 5254) @@ -1,9 +1,26 @@ import sys def docformat(docstring, docdict=None): - ''' Fill a function docstring from variables in dict + ''' Fill a function docstring from variables in dictionary Adapt the indent of the inserted docs + + Parameters + ---------- + docstring : string + docstring from function, possibly with dict formatting strings + docdict : dict + dictionary with keys that match the dict formatting strings + and values that are docstring fragments to be inserted. The + indentation of the inserted docstrings is set to match the + indentation of the ``docstring``. The string values in the + docdict are assumed to have no indent in the first line, and + only indent relative to the first line for following lines. + + Returns + ------- + outstring : string + string with any formatted strings inserted ''' if not docstring: return docstring @@ -29,7 +46,10 @@ def filldoc(docdict): - ''' Return docstring decorator using docdict variable dictionary''' + ''' Return docstring decorator using docdict variable dictionary + + + ''' def decorate(f): f.__doc__ = docformat(f.__doc__, docdict) return f From scipy-svn at scipy.org Sun Dec 14 07:08:39 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 06:08:39 -0600 (CST) Subject: [Scipy-svn] r5255 - trunk/scipy/ndimage Message-ID: <20081214120839.69F12C7C00E@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-14 06:08:36 -0600 (Sun, 14 Dec 2008) New Revision: 5255 Modified: trunk/scipy/ndimage/doccer.py Log: Further small docstrings for the doc formatting module Modified: trunk/scipy/ndimage/doccer.py =================================================================== --- trunk/scipy/ndimage/doccer.py 2008-12-14 12:04:36 UTC (rev 5254) +++ trunk/scipy/ndimage/doccer.py 2008-12-14 12:08:36 UTC (rev 5255) @@ -48,7 +48,15 @@ def filldoc(docdict): ''' Return docstring decorator using docdict variable dictionary + Parameters + ---------- + docdict : dictionary + dictionary containing name, docstring fragment pairs + Returns + ------- + decfunc : function + decorator that applies dictionary to input function docstring ''' def decorate(f): f.__doc__ = docformat(f.__doc__, docdict) From scipy-svn at scipy.org Sun Dec 14 07:53:37 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 06:53:37 -0600 (CST) Subject: [Scipy-svn] r5256 - trunk/doc/source/tutorial Message-ID: <20081214125337.ED409C7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-14 06:53:36 -0600 (Sun, 14 Dec 2008) New Revision: 5256 Modified: trunk/doc/source/tutorial/interpolate.rst Log: added RBF examples from cookbook Modified: trunk/doc/source/tutorial/interpolate.rst =================================================================== --- trunk/doc/source/tutorial/interpolate.rst 2008-12-14 12:08:36 UTC (rev 5255) +++ trunk/doc/source/tutorial/interpolate.rst 2008-12-14 12:53:36 UTC (rev 5256) @@ -5,6 +5,8 @@ .. currentmodule:: scipy.interpolate +.. contents:: + There are two general interpolation facilities available in SciPy. The first facility is an interpolation class which performs linear 1-dimensional interpolation. The second facility is based on the @@ -231,3 +233,84 @@ >>> plt.show() .. :caption: Example of two-dimensional spline interpolation. + +Using radial basis functions for smoothing/interpolation +======================================================== + +Radial basis functions can be used for smoothing/interpolating scattered +data in n-dimensions, but should be used with caution for extrapolation +outside of the observed data range. + +1-d Example +----------- + +This example compares the usage of the Rbf and UnivariateSpline classes +from the scipy.interpolate module. + +.. plot:: + + >>> import numpy as np + >>> from scipy.interpolate import Rbf, InterpolatedUnivariateSpline + >>> import matplotlib.pyplot as plt + + >>> # setup data + >>> x = np.linspace(0, 10, 9) + >>> y = np.sin(x) + >>> xi = np.linspace(0, 10, 101) + + >>> # use fitpack2 method + >>> ius = InterpolatedUnivariateSpline(x, y) + >>> yi = ius(xi) + + >>> plt.subplot(2, 1, 1) + >>> plt.plot(x, y, 'bo') + >>> plt.plot(xi, yi, 'g') + >>> plt.plot(xi, np.sin(xi), 'r') + >>> plt.title('Interpolation using univariate spline') + + >>> # use RBF method + >>> rbf = Rbf(x, y) + >>> fi = rbf(xi) + + >>> plt.subplot(2, 1, 2) + >>> plt.plot(x, y, 'bo') + >>> plt.plot(xi, yi, 'g') + >>> plt.plot(xi, np.sin(xi), 'r') + >>> plt.title('Interpolation using RBF - multiquadrics') + >>> plt.show() + +.. :caption: Example of one-dimensional RBF interpolation. + +2-d Example +----------- + +This example shows how to interpolate scattered 2d data. + +.. plot:: + + >>> import numpy as np + >>> from scipy.interpolate import Rbf + >>> import matplotlib.pyplot as plt + >>> from matplotlib import cm + + >>> # 2-d tests - setup scattered data + >>> x = np.random.rand(100)*4.0-2.0 + >>> y = np.random.rand(100)*4.0-2.0 + >>> z = x*np.exp(-x**2-y**2) + >>> ti = np.linspace(-2.0, 2.0, 100) + >>> XI, YI = np.meshgrid(ti, ti) + + >>> # use RBF + >>> rbf = Rbf(x, y, z, epsilon=2) + >>> ZI = rbf(XI, YI) + + >>> # plot the result + >>> n = plt.normalize(-2., 2.) + >>> plt.subplot(1, 1, 1) + >>> plt.pcolor(XI, YI, ZI, cmap=cm.jet) + >>> plt.scatter(x, y, 100, z, cmap=cm.jet) + >>> plt.title('RBF interpolation - multiquadrics') + >>> plt.xlim(-2, 2) + >>> plt.ylim(-2, 2) + >>> plt.colorbar() + From scipy-svn at scipy.org Sun Dec 14 08:08:16 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 07:08:16 -0600 (CST) Subject: [Scipy-svn] r5257 - trunk/doc/source/tutorial Message-ID: <20081214130816.9E091C7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-14 07:08:09 -0600 (Sun, 14 Dec 2008) New Revision: 5257 Modified: trunk/doc/source/tutorial/interpolate.rst Log: change heading levels Modified: trunk/doc/source/tutorial/interpolate.rst =================================================================== --- trunk/doc/source/tutorial/interpolate.rst 2008-12-14 12:53:36 UTC (rev 5256) +++ trunk/doc/source/tutorial/interpolate.rst 2008-12-14 13:08:09 UTC (rev 5257) @@ -235,14 +235,14 @@ .. :caption: Example of two-dimensional spline interpolation. Using radial basis functions for smoothing/interpolation -======================================================== +--------------------------------------------------------- Radial basis functions can be used for smoothing/interpolating scattered data in n-dimensions, but should be used with caution for extrapolation outside of the observed data range. 1-d Example ------------ +^^^^^^^^^^^ This example compares the usage of the Rbf and UnivariateSpline classes from the scipy.interpolate module. @@ -282,7 +282,7 @@ .. :caption: Example of one-dimensional RBF interpolation. 2-d Example ------------ +^^^^^^^^^^^ This example shows how to interpolate scattered 2d data. From scipy-svn at scipy.org Sun Dec 14 09:05:57 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 08:05:57 -0600 (CST) Subject: [Scipy-svn] r5258 - in trunk/doc/source/tutorial: . examples Message-ID: <20081214140557.AD127C7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-14 08:05:54 -0600 (Sun, 14 Dec 2008) New Revision: 5258 Modified: trunk/doc/source/tutorial/examples/1-1 trunk/doc/source/tutorial/general.rst trunk/doc/source/tutorial/index.rst Log: minor reorganization Modified: trunk/doc/source/tutorial/examples/1-1 =================================================================== --- trunk/doc/source/tutorial/examples/1-1 2008-12-14 13:08:09 UTC (rev 5257) +++ trunk/doc/source/tutorial/examples/1-1 2008-12-14 14:05:54 UTC (rev 5258) @@ -1,4 +1,4 @@ ->>> info(optimize.fmin) +>>> sp.info(optimize.fmin) fmin(func, x0, args=(), xtol=0.0001, ftol=0.0001, maxiter=None, maxfun=None, full_output=0, disp=1, retall=0, callback=None) Modified: trunk/doc/source/tutorial/general.rst =================================================================== --- trunk/doc/source/tutorial/general.rst 2008-12-14 13:08:09 UTC (rev 5257) +++ trunk/doc/source/tutorial/general.rst 2008-12-14 14:05:54 UTC (rev 5258) @@ -1,58 +1,49 @@ -General information -=================== +============ +Introduction +============ -Examples in this tutorial -------------------------- +.. contents:: -Throughout this tutorial it is assumed that the user -has imported all of the names defined in the SciPy top-level namespace -using the command +SciPy is a collection of mathematical algorithms and convenience +functions built on the Numpy extension for Python. It adds +significant power to the interactive Python session by exposing the +user to high-level commands and classes for the manipulation and +visualization of data. With SciPy, an interactive Python session +becomes a data-processing and system-prototyping environment rivaling +sytems such as Matlab, IDL, Octave, R-Lab, and SciLab. - >>> from scipy import * +The additional power of using SciPy within Python, however, is that a +powerful programming language is also available for use in developing +sophisticated programs and specialized applications. Scientific +applications written in SciPy benefit from the development of +additional modules in numerous niche's of the software landscape by +developers across the world. Everything from parallel programming to +web and data-base subroutines and classes have been made available to +the Python programmer. All of this power is available in addition to +the mathematical libraries in SciPy. -Scipy sub-packages need to be imported separately, for example +This document provides a tutorial for the first-time user of SciPy to +help get started with some of the features available in this powerful +package. It is assumed that the user has already installed the +package. Some general Python facility is also assumed such as could be +acquired by working through the Tutorial in the Python distribution. +For further introductory help the user is directed to the Numpy +documentation. - >>> from scipy import linalg, optimize +For brevity and convenience, we will often assume that the main +packages (numpy, scipy, and matplotlib) have been imported as:: + >>> import numpy as np + >>> import scipy as sp + >>> import matplotlib as mpl + >>> import matplotlib.pyplot as plt -Finding Documentation ---------------------- +These are the import conventions that our community has adopted +after discussion on public mailing lists. You will see these +conventions used throughout NumPy and SciPy source code and +documentation. While we obviously don't require you to follow +these conventions in your own code, it is highly recommended. -Scipy and Numpy have HTML and PDF versions of their documentation -available at http://docs.scipy.org/, which currently details nearly -all available functionality. However, this documentation is still -work-in-progress, and some parts may be incomplete or sparse. - -Python also provides the facility of documentation strings. The -functions and classes available in SciPy use this method for on-line -documentation. There are two methods for reading these messages and -getting help. Python provides the command :func:`help` in the pydoc -module. Entering this command with no arguments (i.e. ``>>> help`` ) -launches an interactive help session that allows searching through the -keywords and modules available to all of Python. Running the command -help with an object as the argument displays the calling signature, -and the documentation string of the object. - -The pydoc method of help is sophisticated but uses a pager to display -the text. Sometimes this can interfere with the terminal you are -running the interactive session within. A scipy-specific help system -is also available under the command scipy.info. The signature and -documentation string for the object passed to the help command are -printed to standard output (or to a writeable object passed as the -third argument). The second keyword argument of "scipy.info" defines -the maximum width of the line for printing. If a module is passed as -the argument to help than a list of the functions and classes defined -in that module is printed. For example: - -.. literalinclude:: examples/1-1 - -Another useful command is :func:`source`. When given a function -written in Python as an argument, it prints out a listing of the -source code for that function. This can be helpful in learning about -an algorithm or understanding exactly what a function is doing with -its arguments. Also don't forget about the Python command ``dir`` -which can be used to look at the namespace of a module or package. - SciPy Organization ------------------ @@ -83,6 +74,10 @@ :mod:`weave` C/C++ integration ================== ===================================================================== +Scipy sub-packages need to be imported separately, for example:: + + >>> from scipy import linalg, optimize + Because of their ubiquitousness, some of the functions in these subpackages are also made available in the scipy namespace to ease their use in interactive sessions and programs. In addition, many @@ -90,3 +85,46 @@ top-level of the :mod:`scipy` package. Before looking at the sub-packages individually, we will first look at some of these common functions. + +Finding Documentation +--------------------- + +Scipy and Numpy have HTML and PDF versions of their documentation +available at http://docs.scipy.org/, which currently details nearly +all available functionality. However, this documentation is still +work-in-progress, and some parts may be incomplete or sparse. As +we are a volunteer organization and depend on the community for +growth, your participation--everything from providing feedback to +improving the documentation and code--is welcome and actively +encouraged. + +Python also provides the facility of documentation strings. The +functions and classes available in SciPy use this method for on-line +documentation. There are two methods for reading these messages and +getting help. Python provides the command :func:`help` in the pydoc +module. Entering this command with no arguments (i.e. ``>>> help`` ) +launches an interactive help session that allows searching through the +keywords and modules available to all of Python. Running the command +help with an object as the argument displays the calling signature, +and the documentation string of the object. + +The pydoc method of help is sophisticated but uses a pager to display +the text. Sometimes this can interfere with the terminal you are +running the interactive session within. A scipy-specific help system +is also available under the command ``sp.info``. The signature and +documentation string for the object passed to the ``help`` command are +printed to standard output (or to a writeable object passed as the +third argument). The second keyword argument of ``sp.info`` defines +the maximum width of the line for printing. If a module is passed as +the argument to help than a list of the functions and classes defined +in that module is printed. For example: + +.. literalinclude:: examples/1-1 + +Another useful command is :func:`source`. When given a function +written in Python as an argument, it prints out a listing of the +source code for that function. This can be helpful in learning about +an algorithm or understanding exactly what a function is doing with +its arguments. Also don't forget about the Python command ``dir`` +which can be used to look at the namespace of a module or package. + Modified: trunk/doc/source/tutorial/index.rst =================================================================== --- trunk/doc/source/tutorial/index.rst 2008-12-14 13:08:09 UTC (rev 5257) +++ trunk/doc/source/tutorial/index.rst 2008-12-14 14:05:54 UTC (rev 5258) @@ -4,33 +4,6 @@ .. sectionauthor:: Travis E. Oliphant -SciPy is a collection of mathematical algorithms and convenience -functions built on the Numpy extension for Python. It adds -significant power to the interactive Python session by exposing the -user to high-level commands and classes for the manipulation and -visualization of data. With SciPy, an interactive Python session -becomes a data-processing and system-prototyping environment rivaling -sytems such as Matlab, IDL, Octave, R-Lab, and SciLab. - -The additional power of using SciPy within Python, however, is that a -powerful programming language is also available for use in developing -sophisticated programs and specialized applications. Scientific -applications written in SciPy benefit from the development of -additional modules in numerous niche's of the software landscape by -developers across the world. Everything from parallel programming to -web and data-base subroutines and classes have been made available to -the Python programmer. All of this power is available in addition to -the mathematical libraries in SciPy. - -This document provides a tutorial for the first-time user of SciPy to -help get started with some of the features available in this powerful -package. It is assumed that the user has already installed the -package. Some general Python facility is also assumed such as could be -acquired by working through the Tutorial in the Python distribution. -For further introductory help the user is directed to the Numpy -documentation. - - .. toctree:: :maxdepth: 1 From scipy-svn at scipy.org Sun Dec 14 09:24:21 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 08:24:21 -0600 (CST) Subject: [Scipy-svn] r5259 - trunk/doc/source/tutorial Message-ID: <20081214142421.89C23C7C00E@scipy.org> Author: jarrod.millman Date: 2008-12-14 08:24:19 -0600 (Sun, 14 Dec 2008) New Revision: 5259 Modified: trunk/doc/source/tutorial/basic.rst Log: minor updates Modified: trunk/doc/source/tutorial/basic.rst =================================================================== --- trunk/doc/source/tutorial/basic.rst 2008-12-14 14:05:54 UTC (rev 5258) +++ trunk/doc/source/tutorial/basic.rst 2008-12-14 14:24:19 UTC (rev 5259) @@ -5,6 +5,8 @@ .. currentmodule:: numpy +.. contents:: + Interaction with Numpy ------------------------ @@ -14,12 +16,12 @@ functions (addition, subtraction, division) have been altered to not raise exceptions if floating-point errors are encountered; instead, NaN's and Inf's are returned in the arrays. To assist in detection of -these events, several functions (:func:`isnan`, :func:`isfinite`, -:func:`isinf`) are available. +these events, several functions (:func:`sp.isnan`, :func:`sp.isfinite`, +:func:`sp.isinf`) are available. Finally, some of the basic functions like log, sqrt, and inverse trig functions have been modified to return complex numbers instead of -NaN's where appropriate (*i.e.* ``scipy.sqrt(-1)`` returns ``1j``). +NaN's where appropriate (*i.e.* ``sp.sqrt(-1)`` returns ``1j``). Top-level scipy routines @@ -44,8 +46,8 @@ Type handling ^^^^^^^^^^^^^ -Note the difference between :func:`iscomplex` (:func:`isreal`) and -:func:`iscomplexobj` (:func:`isrealobj`). The former command is +Note the difference between :func:`sp.iscomplex`/:func:`sp.isreal` and +:func:`sp.iscomplexobj`/:func:`sp.isrealobj`. The former command is array based and returns byte arrays of ones and zeros providing the result of the element-wise test. The latter command is object based and returns a scalar describing the result of the test on the entire @@ -55,32 +57,34 @@ complex number. While complex numbers and arrays have attributes that return those values, if one is not sure whether or not the object will be complex-valued, it is better to use the functional forms -:func:`real` and :func:`imag` . These functions succeed for anything +:func:`sp.real` and :func:`sp.imag` . These functions succeed for anything that can be turned into a Numpy array. Consider also the function -:func:`real_if_close` which transforms a complex-valued number with +:func:`sp.real_if_close` which transforms a complex-valued number with tiny imaginary part into a real number. Occasionally the need to check whether or not a number is a scalar (Python (long)int, Python float, Python complex, or rank-0 array) occurs in coding. This functionality is provided in the convenient -function :func:`isscalar` which returns a 1 or a 0. +function :func:`sp.isscalar` which returns a 1 or a 0. Finally, ensuring that objects are a certain Numpy type occurs often enough that it has been given a convenient interface in SciPy through -the use of the :obj:`cast` dictionary. The dictionary is keyed by the +the use of the :obj:`sp.cast` dictionary. The dictionary is keyed by the type it is desired to cast to and the dictionary stores functions to -perform the casting. Thus, ``>>> a = cast['f'](d)`` returns an array -of :class:`float32` from *d*. This function is also useful as an easy -way to get a scalar of a certain type: ``>>> fpi = cast['f'](pi)``. +perform the casting. Thus, ``sp.cast['f'](d)`` returns an array +of :class:`sp.float32` from *d*. This function is also useful as an easy +way to get a scalar of a certain type:: + >>> sp.cast['f'](sp.pi) + array(3.1415927410125732, dtype=float32) Index Tricks ^^^^^^^^^^^^ -Thre are some class instances that make special use of the slicing +There are some class instances that make special use of the slicing functionality to provide efficient means for array construction. This -part will discuss the operation of :obj:`mgrid` , :obj:`ogrid` , -:obj:`r_` , and :obj:`c_` for quickly constructing arrays. +part will discuss the operation of :obj:`sp.mgrid` , :obj:`sp.ogrid` , +:obj:`sp.r_` , and :obj:`sp.c_` for quickly constructing arrays. One familiar with Matlab may complain that it is difficult to construct arrays from the interactive session with Python. Suppose, From scipy-svn at scipy.org Sun Dec 14 12:31:07 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 11:31:07 -0600 (CST) Subject: [Scipy-svn] r5260 - trunk Message-ID: <20081214173107.2FE87C7C00D@scipy.org> Author: ptvirtan Date: 2008-12-14 11:30:56 -0600 (Sun, 14 Dec 2008) New Revision: 5260 Modified: trunk/THANKS.txt Log: THANKS.txt: scipy.optimize.nonlin rewrite is not committed yet, so don't mention it. Modified: trunk/THANKS.txt =================================================================== --- trunk/THANKS.txt 2008-12-14 14:24:19 UTC (rev 5259) +++ trunk/THANKS.txt 2008-12-14 17:30:56 UTC (rev 5260) @@ -33,8 +33,7 @@ Damian Eads -- hierarchical clustering, dendrogram plotting, distance functions in spatial package, vq documentation Anne Archibald -- kd-trees and nearest neighbor in scipy.spatial -Pauli Virtanen -- Sphinx documentation generation, interpolation, - and scipy.nonlin.optimize rewrite. +Pauli Virtanen -- Sphinx documentation generation, interpolation bugfixes. Josef Pktd -- major improvements to scipy.stats and its test suite Testing: From scipy-svn at scipy.org Sun Dec 14 17:42:38 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 16:42:38 -0600 (CST) Subject: [Scipy-svn] r5261 - in trunk/scipy/ndimage: . tests Message-ID: <20081214224238.A2A79C7C00D@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-14 16:42:33 -0600 (Sun, 14 Dec 2008) New Revision: 5261 Modified: trunk/scipy/ndimage/doccer.py trunk/scipy/ndimage/filters.py trunk/scipy/ndimage/tests/test_filters.py Log: New checks for order parameters for Gaussians, with tests Modified: trunk/scipy/ndimage/doccer.py =================================================================== --- trunk/scipy/ndimage/doccer.py 2008-12-14 17:30:56 UTC (rev 5260) +++ trunk/scipy/ndimage/doccer.py 2008-12-14 22:42:33 UTC (rev 5261) @@ -1,3 +1,6 @@ +''' Utilities to allow inserting docstring fragments for common +parameters into function and method docstrings''' + import sys def docformat(docstring, docdict=None): Modified: trunk/scipy/ndimage/filters.py =================================================================== --- trunk/scipy/ndimage/filters.py 2008-12-14 17:30:56 UTC (rev 5260) +++ trunk/scipy/ndimage/filters.py 2008-12-14 22:42:33 UTC (rev 5261) @@ -72,9 +72,6 @@ """origin : scalar, optional The ``origin`` parameter controls the placement of the filter. Default 0""" _extra_arguments_doc = \ -"""extra_arguments : sequence - Sequence of extra positional arguments to pass to passed function""" -_extra_arguments_doc = \ """extra_arguments : sequence, optional Sequence of extra positional arguments to pass to passed function""" _extra_keywords_doc = \ @@ -179,6 +176,8 @@ %(mode)s %(cval)s """ + if order not in range(4): + raise ValueError('Order outside 0..3 not implemented') sd = float(sigma) # make the length of the filter equal to 4 times the standard # deviations: @@ -257,6 +256,8 @@ input = numpy.asarray(input) output, return_value = _ni_support._get_output(output, input) orders = _ni_support._normalize_sequence(order, input.ndim) + if not set(orders).issubset(set(range(4))): + raise ValueError('Order outside 0..4 not implemented') sigmas = _ni_support._normalize_sequence(sigma, input.ndim) axes = range(input.ndim) axes = [(axes[ii], sigmas[ii], orders[ii]) Modified: trunk/scipy/ndimage/tests/test_filters.py =================================================================== --- trunk/scipy/ndimage/tests/test_filters.py 2008-12-14 17:30:56 UTC (rev 5260) +++ trunk/scipy/ndimage/tests/test_filters.py 2008-12-14 22:42:33 UTC (rev 5261) @@ -16,3 +16,15 @@ # The following raises an error unless ticket 701 is fixed res2 = sndi.generic_filter(arr, func, size=1) assert_equal(res, res2) + +def test_orders_gauss(): + # Check order inputs to Gaussians + arr = np.zeros((1,)) + yield assert_equal, 0, sndi.gaussian_filter(arr, 1, order=0) + yield assert_equal, 0, sndi.gaussian_filter(arr, 1, order=3) + yield assert_raises, ValueError, sndi.gaussian_filter, arr, 1, -1 + yield assert_raises, ValueError, sndi.gaussian_filter, arr, 1, 4 + yield assert_equal, 0, sndi.gaussian_filter1d(arr, 1, axis=-1, order=0) + yield assert_equal, 0, sndi.gaussian_filter1d(arr, 1, axis=-1, order=3) + yield assert_raises, ValueError, sndi.gaussian_filter1d, arr, 1, -1, -1 + yield assert_raises, ValueError, sndi.gaussian_filter1d, arr, 1, -1, 4 From scipy-svn at scipy.org Sun Dec 14 23:45:04 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 22:45:04 -0600 (CST) Subject: [Scipy-svn] r5262 - in trunk/scipy/ndimage: . tests Message-ID: <20081215044504.405AEC7C009@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-14 22:45:00 -0600 (Sun, 14 Dec 2008) New Revision: 5262 Modified: trunk/scipy/ndimage/doccer.py trunk/scipy/ndimage/tests/test_doccer.py trunk/scipy/ndimage/tests/test_filters.py Log: Better support for more arbitrary indentation in parameter strings, with tests Modified: trunk/scipy/ndimage/doccer.py =================================================================== --- trunk/scipy/ndimage/doccer.py 2008-12-14 22:42:33 UTC (rev 5261) +++ trunk/scipy/ndimage/doccer.py 2008-12-15 04:45:00 UTC (rev 5262) @@ -29,14 +29,15 @@ return docstring if docdict is None: docdict = {} + if not docdict: + return docstring lines = docstring.expandtabs().splitlines() - # Find the minimum indent of the main docstring, after last line - indentno = sys.maxint - for line in lines[1:]: - stripped = line.lstrip() - if stripped: - indentno = min(indentno, len(line) - len(stripped)) - indent = ' ' * indentno + # Find the minimum indent of the main docstring, after first line + if len(lines) < 2: + icount = 0 + else: + icount = indentcount_lines(lines[1:]) + indent = ' ' * icount # Insert this indent to dictionary docstrings indented = {} for name, dstr in docdict.items(): @@ -48,21 +49,54 @@ return docstring % indented -def filldoc(docdict): +def indentcount_lines(lines): + ''' Minumum indent for all lines in line list ''' + indentno = sys.maxint + for line in lines: + stripped = line.lstrip() + if stripped: + indentno = min(indentno, len(line) - len(stripped)) + if indentno == sys.maxint: + return 0 + return indentno + + +def filldoc(docdict, unindent_params=True): ''' Return docstring decorator using docdict variable dictionary Parameters ---------- docdict : dictionary dictionary containing name, docstring fragment pairs - + unindent_params : {False, True}, boolean, optional + If True, strip common indentation from all parameters in + docdict + Returns ------- decfunc : function decorator that applies dictionary to input function docstring ''' + if unindent_params: + docdict = unindent_dict(docdict) def decorate(f): f.__doc__ = docformat(f.__doc__, docdict) return f return decorate + +def unindent_dict(docdict): + ''' Unindent all strings in a docdict ''' + can_dict = {} + for name, dstr in docdict.items(): + can_dict[name] = unindent_string(dstr) + return can_dict + + +def unindent_string(docstring): + ''' Set docstring to minimum indent for all lines, including first ''' + lines = docstring.expandtabs().splitlines() + icount = indentcount_lines(lines) + if icount == 0: + return docstring + return '\n'.join([line[icount:] for line in lines]) Modified: trunk/scipy/ndimage/tests/test_doccer.py =================================================================== --- trunk/scipy/ndimage/tests/test_doccer.py 2008-12-14 22:42:33 UTC (rev 5261) +++ trunk/scipy/ndimage/tests/test_doccer.py 2008-12-15 04:45:00 UTC (rev 5262) @@ -1,4 +1,4 @@ -''' Some tests for the documenting decorator ''' +''' Some tests for the documenting decorator and support functions ''' import numpy as np @@ -6,20 +6,84 @@ from nose.tools import assert_true -from scipy.ndimage.doccer import docformat, filldoc +import scipy.ndimage.doccer as sndd -def test_docformat(): - docstring = \ - """Docstring - %(strtest)s - """ - param_doc = \ +docstring = \ +"""Docstring + %(strtest1)s + %(strtest2)s + %(strtest3)s +""" +param_doc1 = \ """Another test with some indent""" - formatted = docformat(docstring, {'strtest':param_doc}) - expected = \ + +param_doc2 = \ +"""Another test, one line""" + +param_doc3 = \ +""" Another test + with some indent""" + +doc_dict = {'strtest1':param_doc1, + 'strtest2':param_doc2, + 'strtest3':param_doc3} + +filled_docstring = \ """Docstring Another test with some indent - """ - assert_equal(formatted, expected) + Another test, one line + Another test + with some indent +""" + + +def test_unindent(): + yield assert_equal, sndd.unindent_string(param_doc1), param_doc1 + yield assert_equal, sndd.unindent_string(param_doc2), param_doc2 + yield assert_equal, sndd.unindent_string(param_doc3), param_doc1 + + +def test_unindent_dict(): + d2 = sndd.unindent_dict(doc_dict) + yield assert_equal, d2['strtest1'], doc_dict['strtest1'] + yield assert_equal, d2['strtest2'], doc_dict['strtest2'] + yield assert_equal, d2['strtest3'], doc_dict['strtest1'] + + +def test_docformat(): + udd = sndd.unindent_dict(doc_dict) + formatted = sndd.docformat(docstring, udd) + yield assert_equal, formatted, filled_docstring + single_doc = 'Single line doc %(strtest1)s' + formatted = sndd.docformat(single_doc, doc_dict) + # Note - initial indent of format string does not + # affect subsequent indent of inserted parameter + yield assert_equal, formatted, """Single line doc Another test + with some indent""" + + +def test_decorator(): + # with unindentation of parameters + decorator = sndd.filldoc(doc_dict, True) + @decorator + def func(): + """ Docstring + %(strtest3)s + """ + yield assert_equal, func.__doc__, """ Docstring + Another test + with some indent + """ + # without unindentation of parameters + decorator = sndd.filldoc(doc_dict, False) + @decorator + def func(): + """ Docstring + %(strtest3)s + """ + yield assert_equal, func.__doc__, """ Docstring + Another test + with some indent + """ Modified: trunk/scipy/ndimage/tests/test_filters.py =================================================================== --- trunk/scipy/ndimage/tests/test_filters.py 2008-12-14 22:42:33 UTC (rev 5261) +++ trunk/scipy/ndimage/tests/test_filters.py 2008-12-15 04:45:00 UTC (rev 5262) @@ -8,6 +8,7 @@ import scipy.ndimage as sndi + def test_ticket_701(): # Test generic filter sizes arr = np.arange(4).reshape((2,2)) @@ -17,6 +18,7 @@ res2 = sndi.generic_filter(arr, func, size=1) assert_equal(res, res2) + def test_orders_gauss(): # Check order inputs to Gaussians arr = np.zeros((1,)) From scipy-svn at scipy.org Mon Dec 15 00:23:49 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 23:23:49 -0600 (CST) Subject: [Scipy-svn] r5263 - trunk/scipy/ndimage Message-ID: <20081215052349.35F51C7C009@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-14 23:23:47 -0600 (Sun, 14 Dec 2008) New Revision: 5263 Modified: trunk/scipy/ndimage/doccer.py Log: More docstrings for doccer Modified: trunk/scipy/ndimage/doccer.py =================================================================== --- trunk/scipy/ndimage/doccer.py 2008-12-15 04:45:00 UTC (rev 5262) +++ trunk/scipy/ndimage/doccer.py 2008-12-15 05:23:47 UTC (rev 5263) @@ -16,14 +16,20 @@ dictionary with keys that match the dict formatting strings and values that are docstring fragments to be inserted. The indentation of the inserted docstrings is set to match the - indentation of the ``docstring``. The string values in the - docdict are assumed to have no indent in the first line, and - only indent relative to the first line for following lines. + minimum indentation of the ``docstring``. The string values + in the docdict are assumed to have no indent in the first + line, and only indent relative to the first line for following + lines. Returns ------- outstring : string - string with any formatted strings inserted + string with requested ``docdict`` strings inserted + + Examples + -------- + >>> docformat(' Test string with %(value)s', {'value':'inserted value'}) + ' Test string with inserted value' ''' if not docstring: return docstring @@ -50,7 +56,20 @@ def indentcount_lines(lines): - ''' Minumum indent for all lines in line list ''' + ''' Minumum indent for all lines in line list + + >>> lines = [' one', ' two', ' three'] + >>> indentcount_lines(lines) + 1 + >>> lines = [] + >>> indentcount_lines(lines) + 0 + >>> lines = [' one'] + >>> indentcount_lines(lines) + 1 + >>> indentcount_lines([' ']) + 0 + ''' indentno = sys.maxint for line in lines: stripped = line.lstrip() @@ -76,6 +95,7 @@ ------- decfunc : function decorator that applies dictionary to input function docstring + ''' if unindent_params: docdict = unindent_dict(docdict) @@ -94,7 +114,11 @@ def unindent_string(docstring): - ''' Set docstring to minimum indent for all lines, including first ''' + ''' Set docstring to minimum indent for all lines, including first + + >>> unindent_string(' two') + 'two' + ''' lines = docstring.expandtabs().splitlines() icount = indentcount_lines(lines) if icount == 0: From scipy-svn at scipy.org Mon Dec 15 00:44:38 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 14 Dec 2008 23:44:38 -0600 (CST) Subject: [Scipy-svn] r5264 - trunk/scipy/ndimage Message-ID: <20081215054438.19FBFC7C009@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-14 23:44:37 -0600 (Sun, 14 Dec 2008) New Revision: 5264 Modified: trunk/scipy/ndimage/doccer.py Log: More docstrings for doccer, again ; Modified: trunk/scipy/ndimage/doccer.py =================================================================== --- trunk/scipy/ndimage/doccer.py 2008-12-15 05:23:47 UTC (rev 5263) +++ trunk/scipy/ndimage/doccer.py 2008-12-15 05:44:37 UTC (rev 5264) @@ -16,10 +16,9 @@ dictionary with keys that match the dict formatting strings and values that are docstring fragments to be inserted. The indentation of the inserted docstrings is set to match the - minimum indentation of the ``docstring``. The string values - in the docdict are assumed to have no indent in the first - line, and only indent relative to the first line for following - lines. + minimum indentation of the ``docstring`` by adding this + indentation to all lines of the inserted string, except the + first Returns ------- @@ -30,6 +29,11 @@ -------- >>> docformat(' Test string with %(value)s', {'value':'inserted value'}) ' Test string with inserted value' + >>> docstring = 'First line\\n Second line\\n %(value)s' + >>> inserted_string = "indented\\nstring" + >>> docdict = {'value': inserted_string} + >>> docformat(docstring, docdict) + 'First line\\n Second line\\n indented\\n string' ''' if not docstring: return docstring @@ -118,6 +122,8 @@ >>> unindent_string(' two') 'two' + >>> unindent_string(' two\\n three') + 'two\\n three' ''' lines = docstring.expandtabs().splitlines() icount = indentcount_lines(lines) From scipy-svn at scipy.org Mon Dec 15 13:58:18 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Mon, 15 Dec 2008 12:58:18 -0600 (CST) Subject: [Scipy-svn] r5265 - trunk/scipy/optimize Message-ID: <20081215185818.EF83FC7C040@scipy.org> Author: charris Date: 2008-12-15 12:58:14 -0600 (Mon, 15 Dec 2008) New Revision: 5265 Modified: trunk/scipy/optimize/zeros.py Log: Make disp=True the default. Reformat and clean up documentation. See Also still needs work. Modified: trunk/scipy/optimize/zeros.py =================================================================== --- trunk/scipy/optimize/zeros.py 2008-12-15 05:44:37 UTC (rev 5264) +++ trunk/scipy/optimize/zeros.py 2008-12-15 18:58:14 UTC (rev 5265) @@ -39,57 +39,53 @@ def bisect(f, a, b, args=(), xtol=_xtol, rtol=_rtol, maxiter=_iter, - full_output=False, disp=False): - """Find root of f in [a,b] + full_output=False, disp=True): + """Find root of f in [a,b]. - Basic bisection routine to find a zero of the function - f between the arguments a and b. f(a) and f(b) can not - have the same signs. Slow but sure. + Basic bisection routine to find a zero of the function f between the + arguments a and b. f(a) and f(b) can not have the same signs. Slow but + sure. - f : Python function returning a number. + Parameters + ---------- + f : function + Python function returning a number. f must be continuous, and f(a) and + f(b) must have opposite signs. + a : number + One end of the bracketing interval [a,b]. + b : number + The other end of the bracketing interval [a,b]. + xtol : number, optional + The routine converges when a root is known to lie within xtol of the + value return. Should be >= 0. The routine modifies this to take into + account the relative precision of doubles. + maxiter : number, optional + if convergence is not achieved in maxiter iterations, and error is + raised. Must be >= 0. + args : tuple, optional + containing extra arguments for the function `f`. + `f` is called by ``apply(f, (x)+args)``. + full_output : bool, optional + If `full_output` is False, the root is returned. If `full_output` is + True, the return value is ``(x, r)``, where `x` is the root, and `r` is + a RootResults object. + disp : {True, bool} optional + If True, raise RuntimeError if the algorithm didn't converge. - a : Number, one end of the bracketing interval. + Returns + ------- + x0 : float + Zero of `f` between `a` and `b`. + r : RootResults (present if ``full_output = True``) + Object containing information about the convergence. In particular, + ``r.converged`` is True if the routine converged. - b : Number, the other end of the bracketing interval. + See Also + -------- + brentq, brenth, bisect, newton : one-dimensional root-finding + fixed_point : scalar fixed-point finder + fsolve -- n-dimenstional root-finding - xtol : Number, the routine converges when a root is known - to lie within xtol of the value return. Should be >= 0. - The routine modifies this to take into account the relative - precision of doubles. - - maxiter : Number, if convergence is not achieved in - maxiter iterations, and error is raised. Must be - >= 0. - - args : tuple containing extra arguments for the function f. - f is called by apply(f,(x)+args). - - If full_output is False, the root is returned. - - If full_output is True, the return value is (x, r), where x - is the root, and r is a RootResults object containing information - about the convergence. In particular, r.converged is True if the - the routine converged. - - See also: - - fmin, fmin_powell, fmin_cg, - fmin_bfgs, fmin_ncg -- multivariate local optimizers - leastsq -- nonlinear least squares minimizer - - fmin_l_bfgs_b, fmin_tnc, - fmin_cobyla -- constrained multivariate optimizers - - anneal, brute -- global optimizers - - fminbound, brent, golden, bracket -- local scalar minimizers - - fsolve -- n-dimenstional root-finding - - brentq, brenth, ridder, bisect, newton -- one-dimensional root-finding - - fixed_point -- scalar fixed-point finder - """ if type(args) != type(()) : args = (args,) @@ -98,38 +94,35 @@ def ridder(f, a, b, args=(), xtol=_xtol, rtol=_rtol, maxiter=_iter, - full_output=False, disp=False): + full_output=False, disp=True): """ Find a root of a function in an interval. Parameters ---------- f : function - Python function returning a number. - `f` must be continuous, and `f(a)` and `f(b)` must have opposite signs. + Python function returning a number. f must be continuous, and f(a) and + f(b) must have opposite signs. a : number - one end of the bracketing interval `[a,b]` + One end of the bracketing interval [a,b]. b : number - the other end of the bracketing interval `[a,b]` + The other end of the bracketing interval [a,b]. xtol : number, optional - the routine converges when a root is known - to lie within xtol of the value return. Should be >= 0. - The routine modifies this to take into account the relative - precision of doubles. + The routine converges when a root is known to lie within xtol of the + value return. Should be >= 0. The routine modifies this to take into + account the relative precision of doubles. maxiter : number, optional - if convergence is not achieved in - maxiter iterations, and error is raised. - Must be >= 0. + if convergence is not achieved in maxiter iterations, and error is + raised. Must be >= 0. args : tuple, optional containing extra arguments for the function `f`. `f` is called by ``apply(f, (x)+args)``. full_output : bool, optional - If `full_output` is False, the root is returned. - If `full_output` is True, the return value is ``(x, r)``, where `x` - is the root, and `r` is a RootResults object. - disp : bool, optional - If True, print a message to ``stderr`` if the algorithm didn't - converge. + If `full_output` is False, the root is returned. If `full_output` is + True, the return value is ``(x, r)``, where `x` is the root, and `r` is + a RootResults object. + disp : {True, bool} optional + If True, raise RuntimeError if the algorithm didn't converge. Returns ------- @@ -146,14 +139,14 @@ Notes ----- - Uses [Ridders1979]_ method to find a zero of the function `f` between - the arguments `a` and `b`. Ridders' method is faster than bisection, - but not generaly as fast as the brent rountines. [Ridders1979]_ provides - the classic description and source of the algorithm. A description can - also be found in may be found in any recent edition of Numerical Recipes. + Uses [Ridders1979]_ method to find a zero of the function `f` between the + arguments `a` and `b`. Ridders' method is faster than bisection, but not + generaly as fast as the brent rountines. [Ridders1979]_ provides the + classic description and source of the algorithm. A description can also be + found in may be found in any recent edition of Numerical Recipes. - The routine used here diverges slightly from standard presentations - in order to be a bit more careful of tolerance. + The routine used here diverges slightly from standard presentations in + order to be a bit more careful of tolerance. References ---------- @@ -170,73 +163,66 @@ def brentq(f, a, b, args=(), xtol=_xtol, rtol=_rtol, maxiter=_iter, - full_output=False, disp=False): + full_output=False, disp=True): """ Find a root of a function in given interval. - Return float, a zero of `f` between `a` and `b`. - `f` must be a continuous function, and - [a,b] must be a sign changing interval. + Return float, a zero of `f` between `a` and `b`. `f` must be a continuous + function, and [a,b] must be a sign changing interval. Description: - Uses the classic Brent (1973) method to find a zero - of the function `f` on the sign changing interval [a , b]. - Generally considered the best of the rootfinding routines here. - It is a safe version of the secant method that uses inverse - quadratic extrapolation. - Brent's method combines root bracketing, interval bisection, - and inverse quadratic interpolation. - It is sometimes known as the van Wijngaarden-Deker-Brent method. - Brent (1973) claims convergence is guaranteed for functions - computable within [a,b]. + Uses the classic Brent (1973) method to find a zero of the function `f` on + the sign changing interval [a , b]. Generally considered the best of the + rootfinding routines here. It is a safe version of the secant method that + uses inverse quadratic extrapolation. Brent's method combines root + bracketing, interval bisection, and inverse quadratic interpolation. It is + sometimes known as the van Wijngaarden-Deker-Brent method. Brent (1973) + claims convergence is guaranteed for functions computable within [a,b]. - [Brent1973]_ provides the classic description of the algorithm. - Another description is in any recent edition of Numerical Recipes, - including [PressEtal1992]_. - Another description is at http://mathworld.wolfram.com/BrentsMethod.html. - It should be easy to understand the algorithm just by reading our code. - Our code diverges a bit from standard presentations: - we choose a different formula for the extrapolation step. + [Brent1973]_ provides the classic description of the algorithm. Another + description is in any recent edition of Numerical Recipes, including + [PressEtal1992]_. Another description is at + http://mathworld.wolfram.com/BrentsMethod.html. It should be easy to + understand the algorithm just by reading our code. Our code diverges a bit + from standard presentations: we choose a different formula for the + extrapolation step. - Parameters ---------- + f : function + Python function returning a number. f must be continuous, and f(a) and + f(b) must have opposite signs. + a : number + One end of the bracketing interval [a,b]. + b : number + The other end of the bracketing interval [a,b]. + xtol : number, optional + The routine converges when a root is known to lie within xtol of the + value return. Should be >= 0. The routine modifies this to take into + account the relative precision of doubles. + maxiter : number, optional + if convergence is not achieved in maxiter iterations, and error is + raised. Must be >= 0. + args : tuple, optional + containing extra arguments for the function `f`. + `f` is called by ``apply(f, (x)+args)``. + full_output : bool, optional + If `full_output` is False, the root is returned. If `full_output` is + True, the return value is ``(x, r)``, where `x` is the root, and `r` is + a RootResults object. + disp : {True, bool} optional + If True, raise RuntimeError if the algorithm didn't converge. - `f` : function - Python function returning a number. + Returns + ------- + x0 : float + Zero of `f` between `a` and `b`. + r : RootResults (present if ``full_output = True``) + Object containing information about the convergence. In particular, + ``r.converged`` is True if the routine converged. - `a` : number - one end of the bracketing interval [a,b] - - `b` : number - the other end of the bracketing interval [a,b] - - `xtol` : number - the routine converges when a root is known - to lie within xtol of the value return. Should be >= 0. - The routine modifies this to take into account the relative - precision of doubles. - - `maxiter` : number - if convergence is not achieved in - maxiter iterations, and error is raised. - Must be >= 0. - - `args` : tuple - containing extra arguments for the function `f`. - `f` is called by apply(f,(x)+args). - - `full_output` : bool - If `full_output` is False, the root is returned. - If `full_output` is True, the return value is (x, r), where x - is the root, and r is a RootResults object containing information - about the convergence. In particular, r.converged is True if the - the routine converged. - - See Also -------- - multivariate local optimizers `fmin`, `fmin_powell`, `fmin_cg`, `fmin_bfgs`, `fmin_ncg` nonlinear least squares minimizer @@ -257,8 +243,7 @@ Notes ----- - `f` must be continuous. - f(a) and f(b) must have opposite signs. + f must be continuous. f(a) and f(b) must have opposite signs. .. [Brent1973] @@ -280,45 +265,53 @@ def brenth(f, a, b, args=(), xtol=_xtol, rtol=_rtol, maxiter=_iter, - full_output=False, disp=False): - """Find root of f in [a,b] + full_output=False, disp=True): + """Find root of f in [a,b]. - A variation on the classic Brent routine to find a zero - of the function f between the arguments a and b that uses - hyperbolic extrapolation instead of inverse quadratic - extrapolation. There was a paper back in the 1980's ... - f(a) and f(b) can not have the same signs. Generally on a - par with the brent routine, but not as heavily tested. - It is a safe version of the secant method that uses hyperbolic - extrapolation. The version here is by Chuck Harris. + A variation on the classic Brent routine to find a zero of the function f + between the arguments a and b that uses hyperbolic extrapolation instead of + inverse quadratic extrapolation. There was a paper back in the 1980's ... + f(a) and f(b) can not have the same signs. Generally on a par with the + brent routine, but not as heavily tested. It is a safe version of the + secant method that uses hyperbolic extrapolation. The version here is by + Chuck Harris. - f : Python function returning a number. + Parameters + ---------- + f : function + Python function returning a number. f must be continuous, and f(a) and + f(b) must have opposite signs. + a : number + One end of the bracketing interval [a,b]. + b : number + The other end of the bracketing interval [a,b]. + xtol : number, optional + The routine converges when a root is known to lie within xtol of the + value return. Should be >= 0. The routine modifies this to take into + account the relative precision of doubles. + maxiter : number, optional + if convergence is not achieved in maxiter iterations, and error is + raised. Must be >= 0. + args : tuple, optional + containing extra arguments for the function `f`. + `f` is called by ``apply(f, (x)+args)``. + full_output : bool, optional + If `full_output` is False, the root is returned. If `full_output` is + True, the return value is ``(x, r)``, where `x` is the root, and `r` is + a RootResults object. + disp : {True, bool} optional + If True, raise RuntimeError if the algorithm didn't converge. - a : Number, one end of the bracketing interval. + Returns + ------- + x0 : float + Zero of `f` between `a` and `b`. + r : RootResults (present if ``full_output = True``) + Object containing information about the convergence. In particular, + ``r.converged`` is True if the routine converged. - b : Number, the other end of the bracketing interval. - - xtol : Number, the routine converges when a root is known - to lie within xtol of the value return. Should be >= 0. - The routine modifies this to take into account the relative - precision of doubles. - - maxiter : Number, if convergence is not achieved in - maxiter iterations, and error is raised. Must be - >= 0. - - args : tuple containing extra arguments for the function f. - f is called by apply(f,(x)+args). - - If full_output is False, the root is returned. - - If full_output is True, the return value is (x, r), where x - is the root, and r is a RootResults object containing information - about the convergence. In particular, r.converged is True if the - the routine converged. - - See also: - + See Also + -------- fmin, fmin_powell, fmin_cg, fmin_bfgs, fmin_ncg -- multivariate local optimizers leastsq -- nonlinear least squares minimizer @@ -339,5 +332,5 @@ """ if type(args) != type(()) : args = (args,) - r = _zeros._brenth(f,a,b,xtol,maxiter,args,full_output,disp) + r = _zeros._brenth(f,a, b, xtol, maxiter, args, full_output, disp) return results_c(full_output, r) From scipy-svn at scipy.org Mon Dec 15 13:59:19 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Mon, 15 Dec 2008 12:59:19 -0600 (CST) Subject: [Scipy-svn] r5266 - trunk/scipy/optimize/Zeros Message-ID: <20081215185919.6EB21C7C02E@scipy.org> Author: charris Date: 2008-12-15 12:59:12 -0600 (Mon, 15 Dec 2008) New Revision: 5266 Modified: trunk/scipy/optimize/Zeros/bisect.c trunk/scipy/optimize/Zeros/brenth.c trunk/scipy/optimize/Zeros/brentq.c trunk/scipy/optimize/Zeros/ridder.c Log: Whitespace removal. Modified: trunk/scipy/optimize/Zeros/bisect.c =================================================================== --- trunk/scipy/optimize/Zeros/bisect.c 2008-12-15 18:58:14 UTC (rev 5265) +++ trunk/scipy/optimize/Zeros/bisect.c 2008-12-15 18:59:12 UTC (rev 5266) @@ -7,9 +7,9 @@ { int i; double dm,xm,fm,fa,fb,tol; - + tol = xtol + rtol*(fabs(xa) + fabs(xb)); - + fa = (*f)(xa,params); fb = (*f)(xb,params); params->funcalls = 2; Modified: trunk/scipy/optimize/Zeros/brenth.c =================================================================== --- trunk/scipy/optimize/Zeros/brenth.c 2008-12-15 18:58:14 UTC (rev 5265) +++ trunk/scipy/optimize/Zeros/brenth.c 2008-12-15 18:59:12 UTC (rev 5266) @@ -5,28 +5,28 @@ /* At the top of the loop the situation is the following: - + 1. the root is bracketed between xa and xb 2. xa is the most recent estimate 3. xp is the previous estimate 4. |fp| < |fb| - - The order of xa and xp doesn't matter, but assume xp < xb. Then xa lies to + + The order of xa and xp doesn't matter, but assume xp < xb. Then xa lies to the right of xp and the assumption is that xa is increasing towards the root. In this situation we will attempt quadratic extrapolation as long as the condition - * |fa| < |fp| < |fb| - + * |fa| < |fp| < |fb| + is satisfied. That is, the function value is decreasing as we go along. Note the 4 above implies that the right inequlity already holds. - The first check is that xa is still to the left of the root. If not, xb is + The first check is that xa is still to the left of the root. If not, xb is replaced by xp and the interval reverses, with xb < xa. In this situation - we will try linear interpolation. That this has happened is signaled by the + we will try linear interpolation. That this has happened is signaled by the equality xb == xp; - + The second check is that |fa| < |fb|. If this is not the case, we swap xa and xb and resort to bisection. @@ -39,7 +39,7 @@ double xblk = 0.0, fpre, fcur, fblk = 0.0, spre = 0.0, scur = 0.0, sbis, tol; double stry, dpre, dblk; int i; - + fpre = (*f)(xpre,params); fcur = (*f)(xcur,params); params->funcalls = 2; @@ -48,9 +48,9 @@ if (fcur == 0) return xcur; params->iterations = 0; for(i = 0; i < iter; i++) { - + params->iterations++; - + if (fpre*fcur < 0) { xblk = xpre; fblk = fpre; @@ -60,12 +60,12 @@ xpre = xcur; xcur = xblk; xblk = xpre; fpre = fcur; fcur = fblk; fblk = fpre; } - + tol = xtol + rtol*fabs(xcur); sbis = (xblk - xcur)/2; if (fcur == 0 || fabs(sbis) < tol) return xcur; - + if (fabs(spre) > tol && fabs(fcur) < fabs(fpre)) { if (xpre == xblk) { /* interpolate */ @@ -77,7 +77,7 @@ dblk = (fblk - fcur)/(xblk - xcur); stry = -fcur*(fblk - fpre)/(fblk*dpre - fpre*dblk); } - + if (2*fabs(stry) < DMIN(fabs(spre), 3*fabs(sbis) - tol)) { /* accept step */ spre = scur; scur = stry; @@ -91,13 +91,13 @@ /* bisect */ spre = sbis; scur = sbis; } - + xpre = xcur; fpre = fcur; - if (fabs(scur) > tol) + if (fabs(scur) > tol) xcur += scur; - else + else xcur += (sbis > 0 ? tol : -tol); - + fcur = (*f)(xcur, params); params->funcalls++; } Modified: trunk/scipy/optimize/Zeros/brentq.c =================================================================== --- trunk/scipy/optimize/Zeros/brentq.c 2008-12-15 18:58:14 UTC (rev 5265) +++ trunk/scipy/optimize/Zeros/brentq.c 2008-12-15 18:59:12 UTC (rev 5266) @@ -7,25 +7,25 @@ /* At the top of the loop the situation is the following: - + 1. the root is bracketed between xa and xb 2. xa is the most recent estimate 3. xp is the previous estimate 4. |fp| < |fb| - - The order of xa and xp doesn't matter, but assume xp < xb. Then xa lies to + + The order of xa and xp doesn't matter, but assume xp < xb. Then xa lies to the right of xp and the assumption is that xa is increasing towards the root. In this situation we will attempt quadratic extrapolation as long as the condition - * |fa| < |fp| < |fb| - + * |fa| < |fp| < |fb| + is satisfied. That is, the function value is decreasing as we go along. Note the 4 above implies that the right inequlity already holds. - The first check is that xa is still to the left of the root. If not, xb is + The first check is that xa is still to the left of the root. If not, xb is replaced by xp and the interval reverses, with xb < xa. In this situation - we will try linear interpolation. That this has happened is signaled by the + we will try linear interpolation. That this has happened is signaled by the equality xb == xp; The second check is that |fa| < |fb|. If this is not the case, we swap @@ -40,7 +40,7 @@ double xblk = 0.0, fpre, fcur, fblk = 0.0, spre = 0.0, scur = 0.0, sbis, tol; double stry, dpre, dblk; int i; - + fpre = (*f)(xpre, params); fcur = (*f)(xcur, params); params->funcalls = 2; @@ -59,14 +59,14 @@ xpre = xcur; xcur = xblk; xblk = xpre; fpre = fcur; fcur = fblk; fblk = fpre; } - + tol = xtol + rtol*fabs(xcur); sbis = (xblk - xcur)/2; if (fcur == 0 || fabs(sbis) < tol) return xcur; - + if (fabs(spre) > tol && fabs(fcur) < fabs(fpre)) { - if (xpre == xblk) { + if (xpre == xblk) { /* interpolate */ stry = -fcur*(xcur - xpre)/(fcur - fpre); } @@ -85,19 +85,19 @@ spre = sbis; scur = sbis; } } - else { + else { /* bisect */ spre = sbis; scur = sbis; } - + xpre = xcur; fpre = fcur; if (fabs(scur) > tol) xcur += scur; - else + else xcur += (sbis > 0 ? tol : -tol); - + fcur = (*f)(xcur, params); - params->funcalls++; + params->funcalls++; } ERROR(params,CONVERR, xcur); } Modified: trunk/scipy/optimize/Zeros/ridder.c =================================================================== --- trunk/scipy/optimize/Zeros/ridder.c 2008-12-15 18:58:14 UTC (rev 5265) +++ trunk/scipy/optimize/Zeros/ridder.c 2008-12-15 18:59:12 UTC (rev 5266) @@ -9,7 +9,7 @@ double ridder(callback_type f, double xa, double xb, double xtol, double rtol, int iter, default_parameters *params) -{ +{ int i; double dm,dn,xm,xn=0.0,fn,fm,fa,fb,tol; From scipy-svn at scipy.org Mon Dec 15 14:01:40 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Mon, 15 Dec 2008 13:01:40 -0600 (CST) Subject: [Scipy-svn] r5267 - trunk/scipy/optimize Message-ID: <20081215190140.AB993C7C00C@scipy.org> Author: charris Date: 2008-12-15 13:01:36 -0600 (Mon, 15 Dec 2008) New Revision: 5267 Modified: trunk/scipy/optimize/zeros.c Log: Make 1d solvers raise RuntimeError when disp=True and there is a failure to converge. Modified: trunk/scipy/optimize/zeros.c =================================================================== --- trunk/scipy/optimize/zeros.c 2008-12-15 18:59:12 UTC (rev 5266) +++ trunk/scipy/optimize/zeros.c 2008-12-15 19:01:36 UTC (rev 5267) @@ -10,7 +10,7 @@ typedef struct { int funcalls; int iterations; - int error_num; + int error_num; PyObject *function; PyObject *args; jmp_buf env; @@ -28,7 +28,7 @@ static double scipy_zeros_rtol=0; -double +double scipy_zeros_functions_func(double x, void *params) { scipy_zeros_parameters *myparams = params; @@ -37,14 +37,14 @@ args = myparams->args; f = myparams->function; - PyTuple_SetItem(args,0,Py_BuildValue("d",x)); + PyTuple_SetItem(args, 0, Py_BuildValue("d",x)); retval=PyObject_CallObject(f,args); - if (retval==NULL) { + if (retval == NULL) { longjmp(myparams->env, 1); } val = PyFloat_AsDouble(retval); Py_XDECREF(retval); - return val; + return val; } /* @@ -53,68 +53,87 @@ static PyObject * call_solver(solver_type solver, PyObject *self, PyObject *args) -{ +{ double a,b,xtol,zero; int iter,i, len, fulloutput, disp=1, flag=0; scipy_zeros_parameters params; jmp_buf env; - PyObject *f,*xargs,*item,*fargs=NULL; + PyObject *f, *xargs, *item, *fargs=NULL; - if (!PyArg_ParseTuple(args,"OdddiOi|i",&f,&a,&b,&xtol,&iter,&xargs,&fulloutput,&disp)) + if (!PyArg_ParseTuple(args, "OdddiOi|i", + &f, &a, &b, &xtol, &iter, &xargs, &fulloutput, &disp)) { - PyErr_SetString(PyExc_RuntimeError,"Unable to parse arguments"); + PyErr_SetString(PyExc_RuntimeError, "Unable to parse arguments"); return NULL; } if (xtol < 0) { - PyErr_SetString(PyExc_ValueError,"xtol must be >= 0"); + PyErr_SetString(PyExc_ValueError, "xtol must be >= 0"); return NULL; } if (iter < 0) { - PyErr_SetString(PyExc_ValueError,"maxiter should be > 0"); + PyErr_SetString(PyExc_ValueError, "maxiter should be > 0"); return NULL; } - + len = PyTuple_Size(xargs); - fargs = PyTuple_New(len + 1); /* room for the double - as the first argument */ + /* Make room for the double as first argument */ + fargs = PyTuple_New(len + 1); if (fargs == NULL) { - PyErr_SetString(PyExc_RuntimeError,"Failed to allocate argument tuple"); + PyErr_SetString(PyExc_RuntimeError, + "Failed to allocate argument tuple"); return NULL; } for (i = 0; i < len; i++) { item = PyTuple_GetItem(xargs, i); - if (item == NULL) { Py_DECREF(fargs); return NULL;} + if (item == NULL) { + Py_DECREF(fargs); + return NULL; + } Py_INCREF(item); - PyTuple_SET_ITEM(fargs,i+1,item); + PyTuple_SET_ITEM(fargs, i+1, item); } params.function = f; params.args = fargs; - if (!setjmp(env)) { /* direct return */ - memcpy(params.env,env,sizeof(jmp_buf)); + if (!setjmp(env)) { + /* direct return */ + memcpy(params.env, env, sizeof(jmp_buf)); params.error_num = 0; - zero = solver(scipy_zeros_functions_func,a,b,xtol,scipy_zeros_rtol,iter, (default_parameters*)¶ms); + zero = solver(scipy_zeros_functions_func, a, b, + xtol, scipy_zeros_rtol, iter, (default_parameters*)¶ms); Py_DECREF(fargs); if (params.error_num != 0) { if (params.error_num == SIGNERR) { - PyErr_SetString(PyExc_ValueError,"f(a) and f(b) must have different signs"); + PyErr_SetString(PyExc_ValueError, + "f(a) and f(b) must have different signs"); return NULL; } if (params.error_num == CONVERR) { if (disp) { - fprintf(stderr, "Warning: failed to converge after %d iterations.\n", params.iterations); + char msg[100]; + PyOS_snprintf(msg, sizeof(msg), + "Failed to converge after %d iterations.", + params.iterations); + PyErr_SetString(PyExc_RuntimeError, msg); flag = 1; + return NULL; } } } - if (fulloutput) return Py_BuildValue("diii",zero,params.funcalls,params.iterations,flag); - else return Py_BuildValue("d",zero); + if (fulloutput) { + return Py_BuildValue("diii", + zero, params.funcalls, params.iterations, flag); + } + else { + return Py_BuildValue("d", zero); + } } - else { /* error return from Python function */ + else { + /* error return from Python function */ Py_DECREF(fargs); - return NULL; + return NULL; } } @@ -150,7 +169,7 @@ * Standard Python module inteface */ -static PyMethodDef +static PyMethodDef Zerosmethods[] = { {"_bisect", _bisect, METH_VARARGS, "a"}, {"_ridder", _ridder, METH_VARARGS, "a"}, From scipy-svn at scipy.org Tue Dec 16 04:35:01 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 16 Dec 2008 03:35:01 -0600 (CST) Subject: [Scipy-svn] r5268 - in trunk/scipy/interpolate: . tests Message-ID: <20081216093501.48481C7C029@scipy.org> Author: ptvirtan Date: 2008-12-16 03:34:47 -0600 (Tue, 16 Dec 2008) New Revision: 5268 Modified: trunk/scipy/interpolate/interpolate.py trunk/scipy/interpolate/tests/test_interpolate.py Log: interp1d: Fix spurious casting of complex data to real. Fail early with complex data + splines -- these don't work yet due to _fitpack.bisplev being written in C. Add tests with complex data Modified: trunk/scipy/interpolate/interpolate.py =================================================================== --- trunk/scipy/interpolate/interpolate.py 2008-12-15 19:01:36 UTC (rev 5267) +++ trunk/scipy/interpolate/interpolate.py 2008-12-16 09:34:47 UTC (rev 5268) @@ -217,7 +217,7 @@ raise ValueError("the y array must have at least one dimension.") # Force-cast y to a floating-point type, if it's not yet one - if not isinstance(y.dtype.type, np.inexact): + if not issubclass(y.dtype.type, np.inexact): y = y.astype(np.float_) # Normalize the axis to ensure that it is positive. @@ -248,6 +248,9 @@ self._call = self._call_spline self._spline = splmake(x,oriented_y,order=order) + if issubclass(y.dtype.type, np.complexfloating): + raise ValueError("Input data must be real for spline interpolation") + len_x = len(x) if len_x != len_y: raise ValueError("x and y arrays must be equal in length along " Modified: trunk/scipy/interpolate/tests/test_interpolate.py =================================================================== --- trunk/scipy/interpolate/tests/test_interpolate.py 2008-12-15 19:01:36 UTC (rev 5267) +++ trunk/scipy/interpolate/tests/test_interpolate.py 2008-12-16 09:34:47 UTC (rev 5268) @@ -292,6 +292,35 @@ yield self._nd_check_interp, kind yield self._nd_check_shape, kind + def _check_complex(self, dtype=np.complex_, kind='linear', fail=False): + x = np.arange(10).astype(np.int_) + y = np.arange(10).astype(np.int_) * (1 + 2j) + y = y.astype(dtype) + if fail: + assert_raises(ValueError, interp1d, x, y, kind=kind) + else: + c = interp1d(x, y, kind=kind) + assert_array_almost_equal(y[:-1], c(x)[:-1]) + assert (y.dtype == dtype) or not issubclass(y.dtype.type, np.inexact) + + def test_complex(self): + for kind in ('linear', 'nearest'): + yield self._check_complex, np.complex64, kind + yield self._check_complex, np.complex128, kind + yield self._check_complex, np.float32, kind + yield self._check_complex, np.float64, kind + + # The spline methods can't handle complex values, because the code + # for _fitpack.bispleval is written in C and is not type-agnostic. + # + # Check that a ValueError is raised if one attempts to interpolate + # complex data using these routines. + for kind in ('cubic', 'slinear', 'quadratic', 'zero'): + yield self._check_complex, np.complex64, kind, True + yield self._check_complex, np.complex128, kind, True + yield self._check_complex, np.float32, kind + yield self._check_complex, np.float64, kind + @dec.knownfailureif(True, "zero-order splines fail for the last point") def test_nd_zero_spline(self): # zero-order splines don't get the last point right, From scipy-svn at scipy.org Tue Dec 16 05:46:30 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 16 Dec 2008 04:46:30 -0600 (CST) Subject: [Scipy-svn] r5269 - trunk Message-ID: <20081216104630.0C907C7C02A@scipy.org> Author: jarrod.millman Date: 2008-12-16 04:46:27 -0600 (Tue, 16 Dec 2008) New Revision: 5269 Modified: trunk/THANKS.txt Log: cleaning up THANKS Modified: trunk/THANKS.txt =================================================================== --- trunk/THANKS.txt 2008-12-16 09:34:47 UTC (rev 5268) +++ trunk/THANKS.txt 2008-12-16 10:46:27 UTC (rev 5269) @@ -1,18 +1,14 @@ SciPy is an open source library of routines for science and engineering using Python. It is a community project sponsored by Enthought, Inc. -Many people have contributed to SciPy, both in code development, +SciPy originated with code contributions by Travis Oliphant, Pearu +Peterson, and Eric Jones. Travis Oliphant and Eric Jones each contributed +about half the initial code. Pearu Peterson developed f2py, which is the +integral to wrapping the many Fortran libraries used in SciPy. + +Since then many people have contributed to SciPy, both in code development, suggestions, and financial support. Below is a partial list. If you've -been left off, please let me know (eric at enthought.com), and I'll add -your name. +been left off, please email the "SciPy Developers List" . -Code Contributions: - -The main developers on SciPy are Travis Oliphant, Pearu Peterson, and Eric -Jones. Travis and Eric each contributed about half the orginal code. Pearu -developed f2py, which is the integral to wrapping the many Fortran libraries -used in SciPy. All three continually work on both algorithm development and -improvements to the feature set, build process, and robustness of SciPy. - Please add names as needed so that we can keep up with all the contributors. Kumar Appaiah -- Dolph Chebyshev window @@ -34,7 +30,7 @@ distance functions in spatial package, vq documentation Anne Archibald -- kd-trees and nearest neighbor in scipy.spatial Pauli Virtanen -- Sphinx documentation generation, interpolation bugfixes. -Josef Pktd -- major improvements to scipy.stats and its test suite +Josef Perktold -- major improvements to scipy.stats and its test suite Testing: From scipy-svn at scipy.org Tue Dec 16 06:04:10 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 16 Dec 2008 05:04:10 -0600 (CST) Subject: [Scipy-svn] r5270 - trunk Message-ID: <20081216110410.80F2AC7C02A@scipy.org> Author: jarrod.millman Date: 2008-12-16 05:04:08 -0600 (Tue, 16 Dec 2008) New Revision: 5270 Modified: trunk/THANKS.txt Log: more consistent with the NumPy Thanks Modified: trunk/THANKS.txt =================================================================== --- trunk/THANKS.txt 2008-12-16 10:46:27 UTC (rev 5269) +++ trunk/THANKS.txt 2008-12-16 11:04:08 UTC (rev 5270) @@ -11,49 +11,37 @@ Please add names as needed so that we can keep up with all the contributors. -Kumar Appaiah -- Dolph Chebyshev window -Nathan Bell -- sparsetools, help with scipy.sparse and scipy.splinalg -Robert Cimrman -- UMFpack wrapper for sparse matrix module -David M. Cooke -- improvements to system_info, and LBFGSB wrapper -Aric Hagberg -- ARPACK wrappers, help with splinalg.eigen -Chuck Harris -- Zeros package in optimize (1d root-finding algorithms) -Prabhu Ramachandran -- improvements to gui_thread -Robert Kern -- improvements to stats and bug-fixes -Jean-Sebastien Roy -- fmin_tnc code which he adapted from Stephen Nash's - original Fortran -Ed Schofield -- Maximum entropy and Monte Carlo modules, help with - sparse matrix module -Travis Vaught -- initial work on stats module clean up -Jeff Whitaker -- Mac OS X support -David Cournapeau -- bug-fixes, refactor of fftpack and cluster, numscons build. -Damian Eads -- hierarchical clustering, dendrogram plotting, - distance functions in spatial package, vq documentation -Anne Archibald -- kd-trees and nearest neighbor in scipy.spatial -Pauli Virtanen -- Sphinx documentation generation, interpolation bugfixes. -Josef Perktold -- major improvements to scipy.stats and its test suite - -Testing: - +Kumar Appaiah for Dolph Chebyshev window +Nathan Bell for sparsetools, help with scipy.sparse and scipy.splinalg +Robert Cimrman for UMFpack wrapper for sparse matrix module +David M. Cooke for improvements to system_info, and LBFGSB wrapper +Aric Hagberg for ARPACK wrappers, help with splinalg.eigen +Chuck Harris for Zeros package in optimize (1d root-finding algorithms) +Prabhu Ramachandran for improvements to gui_thread +Robert Kern for improvements to stats and bug-fixes +Jean-Sebastien Roy for fmin_tnc code which he adapted from Stephen Nash's + original Fortran +Ed Schofield for Maximum entropy and Monte Carlo modules, help with + sparse matrix module +Travis Vaught for numerous contributions to annual conference and community + web-site and the initial work on stats module clean up +Jeff Whitaker for Mac OS X support +David Cournapeau for bug-fixes, refactor of fftpack and cluster, numscons build. +Damian Eads for hierarchical clustering, dendrogram plotting, + distance functions in spatial package, vq documentation +Anne Archibald for kd-trees and nearest neighbor in scipy.spatial +Pauli Virtanen for Sphinx documentation generation, interpolation bugfixes. +Josef Perktold for major improvements to scipy.stats and its test suite David Morrill for getting the scoreboard test system up and running. Louis Luangkesorn for providing multiple tests for the stats module. +Jochen Kupper for the zoom feature in the now-deprecated plt plotting module +Tiffany Kamm for working on the community web-site. +Mark Koudritsky for maintaining the web-site +Andrew Straw for setting up the new Wiki at scipy.org +Institutions +------------ -Others: - -Others who have contributed in the past include: - -Jochen Kupper -- the zoom feature in the now-deprecated plt plotting module - - -Website Development: - -Travis Vaught, Tiffany Kamm, and Eric Jones -- for building the community web-site. -Travis Vaught, Mark Koudritsky -- for maintaining the web-site -Andrew Straw -- for setting up the new Wiki at scipy.org - - -Institutions: - Enthought -- for providing resources and finances for development of SciPy. Brigham Young University -- for providing resources for students to work on SciPy. Agilent -- which gave a genereous donation for support of SciPy. From scipy-svn at scipy.org Tue Dec 16 06:27:00 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 16 Dec 2008 05:27:00 -0600 (CST) Subject: [Scipy-svn] r5271 - trunk Message-ID: <20081216112700.6D362C7C029@scipy.org> Author: jarrod.millman Date: 2008-12-16 05:26:58 -0600 (Tue, 16 Dec 2008) New Revision: 5271 Modified: trunk/THANKS.txt Log: added more contributors Modified: trunk/THANKS.txt =================================================================== --- trunk/THANKS.txt 2008-12-16 11:04:08 UTC (rev 5270) +++ trunk/THANKS.txt 2008-12-16 11:26:58 UTC (rev 5271) @@ -37,12 +37,20 @@ Jochen Kupper for the zoom feature in the now-deprecated plt plotting module Tiffany Kamm for working on the community web-site. Mark Koudritsky for maintaining the web-site -Andrew Straw for setting up the new Wiki at scipy.org +Andrew Straw for help with the web-page, documentation, packaging and + testing. +Stefan van der Walt for numerous bug-fixes, testing and documentation. +Jarrod Millman for release management, community coordination, and code + clean up. +Pierre Gerard-Marchant for statistical masked array functionality. +Alan McIntyre for updating SciPy tests to use the new NumPy test framework. + Institutions ------------ -Enthought -- for providing resources and finances for development of SciPy. -Brigham Young University -- for providing resources for students to work on SciPy. -Agilent -- which gave a genereous donation for support of SciPy. +Enthought for providing resources and finances for development of SciPy. +Brigham Young University for providing resources for students to work on SciPy. +Agilent which gave a genereous donation for support of SciPy. +UC Berkeley for providing travel money and hosting numerous sprints. From scipy-svn at scipy.org Tue Dec 16 06:59:11 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 16 Dec 2008 05:59:11 -0600 (CST) Subject: [Scipy-svn] r5272 - trunk Message-ID: <20081216115911.B8A94C7C029@scipy.org> Author: jarrod.millman Date: 2008-12-16 05:59:09 -0600 (Tue, 16 Dec 2008) New Revision: 5272 Modified: trunk/THANKS.txt Log: more people to Thank Modified: trunk/THANKS.txt =================================================================== --- trunk/THANKS.txt 2008-12-16 11:26:58 UTC (rev 5271) +++ trunk/THANKS.txt 2008-12-16 11:59:09 UTC (rev 5272) @@ -44,8 +44,13 @@ clean up. Pierre Gerard-Marchant for statistical masked array functionality. Alan McIntyre for updating SciPy tests to use the new NumPy test framework. +Matthew Brett for work on the Matlab file IO, bug-fixes, and improvements + to the testing framework. +Gary Strangman for the scipy.stats package. +Tiziano Zito for generalized symmetric and hermitian eigenvalue problem + solver. +Chris Burns for bug-fixes. - Institutions ------------ From scipy-svn at scipy.org Tue Dec 16 20:37:24 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 16 Dec 2008 19:37:24 -0600 (CST) Subject: [Scipy-svn] r5273 - trunk/doc/source/tutorial Message-ID: <20081217013724.C9B3CC7C00F@scipy.org> Author: david.warde-farley Date: 2008-12-16 19:37:08 -0600 (Tue, 16 Dec 2008) New Revision: 5273 Added: trunk/doc/source/tutorial/ndimage.rst Log: Testing to see if I can commit. Added: trunk/doc/source/tutorial/ndimage.rst =================================================================== --- trunk/doc/source/tutorial/ndimage.rst 2008-12-16 11:59:09 UTC (rev 5272) +++ trunk/doc/source/tutorial/ndimage.rst 2008-12-17 01:37:08 UTC (rev 5273) @@ -0,0 +1,2 @@ +Multi-dimensional image processing +================================== From scipy-svn at scipy.org Wed Dec 17 21:51:49 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 17 Dec 2008 20:51:49 -0600 (CST) Subject: [Scipy-svn] r5274 - trunk/scipy/optimize Message-ID: <20081218025149.36A62C7C01D@scipy.org> Author: josef Date: 2008-12-17 20:51:45 -0600 (Wed, 17 Dec 2008) New Revision: 5274 Modified: trunk/scipy/optimize/__init__.py trunk/scipy/optimize/info.py Log: add nnls to optimize __all__ and info Modified: trunk/scipy/optimize/__init__.py =================================================================== --- trunk/scipy/optimize/__init__.py 2008-12-17 01:37:08 UTC (rev 5273) +++ trunk/scipy/optimize/__init__.py 2008-12-18 02:51:45 UTC (rev 5274) @@ -14,6 +14,7 @@ from nonlin import broyden1, broyden2, broyden3, broyden_generalized, \ anderson, anderson2 from slsqp import fmin_slsqp +from nnls import nnls __all__ = filter(lambda s:not s.startswith('_'),dir()) from numpy.testing import Tester Modified: trunk/scipy/optimize/info.py =================================================================== --- trunk/scipy/optimize/info.py 2008-12-17 01:37:08 UTC (rev 5273) +++ trunk/scipy/optimize/info.py 2008-12-18 02:51:45 UTC (rev 5274) @@ -27,6 +27,9 @@ fmin_cobyla -- Constrained Optimization BY Linear Approximation + nnls -- Solve linear least squares problem with non-negativity + constraint + Global Optimizers:: anneal -- Simulated Annealing From scipy-svn at scipy.org Thu Dec 18 15:32:27 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 18 Dec 2008 14:32:27 -0600 (CST) Subject: [Scipy-svn] r5275 - in trunk/scipy/interpolate: . tests Message-ID: <20081218203227.9EBCCC7C011@scipy.org> Author: ptvirtan Date: 2008-12-18 14:32:14 -0600 (Thu, 18 Dec 2008) New Revision: 5275 Modified: trunk/scipy/interpolate/interpolate.py trunk/scipy/interpolate/tests/test_interpolate.py Log: interp1d/spleval: enable spline interpolation of complex-valued data, by evaluating real and imaginary parts separately Modified: trunk/scipy/interpolate/interpolate.py =================================================================== --- trunk/scipy/interpolate/interpolate.py 2008-12-18 02:51:45 UTC (rev 5274) +++ trunk/scipy/interpolate/interpolate.py 2008-12-18 20:32:14 UTC (rev 5275) @@ -248,9 +248,6 @@ self._call = self._call_spline self._spline = splmake(x,oriented_y,order=order) - if issubclass(y.dtype.type, np.complexfloating): - raise ValueError("Input data must be real for spline interpolation") - len_x = len(x) if len_x != len_y: raise ValueError("x and y arrays must be equal in length along " @@ -765,10 +762,14 @@ oldshape = np.shape(xnew) xx = np.ravel(xnew) sh = cvals.shape[1:] - res = np.empty(xx.shape + sh) + res = np.empty(xx.shape + sh, dtype=cvals.dtype) for index in np.ndindex(*sh): sl = (slice(None),)+index - res[sl] = _fitpack._bspleval(xx,xj,cvals[sl],k,deriv) + if issubclass(cvals.dtype.type, np.complexfloating): + res[sl].real = _fitpack._bspleval(xx,xj,cvals.real[sl],k,deriv) + res[sl].imag = _fitpack._bspleval(xx,xj,cvals.imag[sl],k,deriv) + else: + res[sl] = _fitpack._bspleval(xx,xj,cvals[sl],k,deriv) res.shape = oldshape + sh return res Modified: trunk/scipy/interpolate/tests/test_interpolate.py =================================================================== --- trunk/scipy/interpolate/tests/test_interpolate.py 2008-12-18 02:51:45 UTC (rev 5274) +++ trunk/scipy/interpolate/tests/test_interpolate.py 2008-12-18 20:32:14 UTC (rev 5275) @@ -292,35 +292,28 @@ yield self._nd_check_interp, kind yield self._nd_check_shape, kind - def _check_complex(self, dtype=np.complex_, kind='linear', fail=False): - x = np.arange(10).astype(np.int_) - y = np.arange(10).astype(np.int_) * (1 + 2j) + def _check_complex(self, dtype=np.complex_, kind='linear'): + x = np.array([1, 2.5, 3, 3.1, 4, 6.4, 7.9, 8.0, 9.5, 10]) + y = x * x ** (1 + 2j) y = y.astype(dtype) - if fail: - assert_raises(ValueError, interp1d, x, y, kind=kind) - else: - c = interp1d(x, y, kind=kind) - assert_array_almost_equal(y[:-1], c(x)[:-1]) - assert (y.dtype == dtype) or not issubclass(y.dtype.type, np.inexact) + # simple test + c = interp1d(x, y, kind=kind) + assert_array_almost_equal(y[:-1], c(x)[:-1]) + + # check against interpolating real+imag separately + xi = np.linspace(1, 10, 31) + cr = interp1d(x, y.real, kind=kind) + ci = interp1d(x, y.imag, kind=kind) + assert_array_almost_equal(c(xi).real, cr(xi)) + assert_array_almost_equal(c(xi).imag, ci(xi)) + def test_complex(self): - for kind in ('linear', 'nearest'): + for kind in ('linear', 'nearest', 'cubic', 'slinear', 'quadratic', + 'zero'): yield self._check_complex, np.complex64, kind yield self._check_complex, np.complex128, kind - yield self._check_complex, np.float32, kind - yield self._check_complex, np.float64, kind - # The spline methods can't handle complex values, because the code - # for _fitpack.bispleval is written in C and is not type-agnostic. - # - # Check that a ValueError is raised if one attempts to interpolate - # complex data using these routines. - for kind in ('cubic', 'slinear', 'quadratic', 'zero'): - yield self._check_complex, np.complex64, kind, True - yield self._check_complex, np.complex128, kind, True - yield self._check_complex, np.float32, kind - yield self._check_complex, np.float64, kind - @dec.knownfailureif(True, "zero-order splines fail for the last point") def test_nd_zero_spline(self): # zero-order splines don't get the last point right, From scipy-svn at scipy.org Thu Dec 18 15:43:00 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 18 Dec 2008 14:43:00 -0600 (CST) Subject: [Scipy-svn] r5276 - trunk/scipy/optimize/tests Message-ID: <20081218204300.543BEC7C00B@scipy.org> Author: ptvirtan Date: 2008-12-18 14:42:29 -0600 (Thu, 18 Dec 2008) New Revision: 5276 Modified: trunk/scipy/optimize/tests/test_nnls.py Log: Adapt nnls test to changed import Modified: trunk/scipy/optimize/tests/test_nnls.py =================================================================== --- trunk/scipy/optimize/tests/test_nnls.py 2008-12-18 20:32:14 UTC (rev 5275) +++ trunk/scipy/optimize/tests/test_nnls.py 2008-12-18 20:42:29 UTC (rev 5276) @@ -16,7 +16,7 @@ a=arange(25.0).reshape(-1,5) x=arange(5.0) y=dot(a,x) - x, res= nnls.nnls(a,y) + x, res= nnls(a,y) assert res<1e-7 assert norm(dot(a,x)-y)<1e-7 From scipy-svn at scipy.org Thu Dec 18 18:50:26 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Thu, 18 Dec 2008 17:50:26 -0600 (CST) Subject: [Scipy-svn] r5277 - trunk/doc/source/tutorial Message-ID: <20081218235026.1157FC7C00B@scipy.org> Author: david.warde-farley Date: 2008-12-18 17:49:30 -0600 (Thu, 18 Dec 2008) New Revision: 5277 Modified: trunk/doc/source/tutorial/ndimage.rst Log: First pass at the conversion of the old numarray stuff. Sphinx references and some other roles are marked from available markup, stuff in {} need a careful look. Modified: trunk/doc/source/tutorial/ndimage.rst =================================================================== --- trunk/doc/source/tutorial/ndimage.rst 2008-12-18 20:42:29 UTC (rev 5276) +++ trunk/doc/source/tutorial/ndimage.rst 2008-12-18 23:49:30 UTC (rev 5277) @@ -1,2 +1,1805 @@ Multi-dimensional image processing ================================== + +{Peter Verveer} {verveer at users.sourceforge.net} +{Multidimensional image analysis functions} + +.. _ndimage_introduction: + +Introduction +============ + +Image processing and analysis are generally seen as operations on +two-dimensional arrays of values. There are however a number of +fields where images of higher dimensionality must be analyzed. Good +examples of these are medical imaging and biological imaging. +{numarray} is suited very well for this type of applications due +its inherent multi-dimensional nature. The {numarray.nd_image} +packages provides a number of general image processing and analysis +functions that are designed to operate with arrays of arbitrary +dimensionality. The packages currently includes functions for +linear and non-linear filtering, binary morphology, B-spline +interpolation, and object measurements. + +.. _ndimage_properties_shared_by_all_functions: + +Properties shared by all functions +================================== + +All functions share some common properties. Notably, all functions +allow the specification of an output array with the {output} +argument. With this argument you can specify an array that will be +changed in-place with the result with the operation. In this case +the result is not returned. Usually, using the {output} argument is +more efficient, since an existing array is used to store the +result. + +The type of arrays returned is dependent on the type of operation, +but it is in most cases equal to the type of the input. If, +however, the {output} argument is used, the type of the result is +equal to the type of the specified output argument. If no output +argument is given, it is still possible to specify what the result +of the output should be. This is done by simply assigning the +desired numarray type object to the output argument. For example: + +:: + + >>> print correlate(arange(10), [1, 2.5]) + [ 0 2 6 9 13 16 20 23 27 30] + >>> print correlate(arange(10), [1, 2.5], output = Float64) + [ 0. 2.5 6. 9.5 13. 16.5 20. 23.5 27. 30.5] + +{In previous versions of :mod:`scipy.ndimage`, some functions accepted the *output_type* argument to achieve the same effect. This argument is still supported, but its use will generate an deprecation warning. In a future version all instances of this argument will be removed. The preferred way to specify an output type, is by using the *output* argument, either by specifying an output array of the desired type, or by specifying the type of the output that is to be returned.} + +Filter functions +================ + +.. _ndimage_filter_functions: + +The functions described in this section all perform some type of spatial filtering of the the input array: the elements in the output are some function of the values in the neighborhood of the corresponding input element. We refer to this neighborhood of elements as the filter kernel, which is often +rectangular in shape but may also have an arbitrary footprint. Many +of the functions described below allow you to define the footprint +of the kernel, by passing a mask through the {footprint} parameter. +For example a cross shaped kernel can be defined as follows: + +:: + + >>> footprint = array([[0,1,0],[1,1,1],[0,1,0]]) + >>> print footprint + [[0 1 0] + [1 1 1] + [0 1 0]] + +Usually the origin of the kernel is at the center calculated by +dividing the dimensions of the kernel shape by two. For instance, +the origin of a one-dimensional kernel of length three is at the +second element. Take for example the correlation of a +one-dimensional array with a filter of length 3 consisting of +ones: + +:: + + >>> a = [0, 0, 0, 1, 0, 0, 0] + >>> correlate1d(a, [1, 1, 1]) + [0 0 1 1 1 0 0] + +Sometimes it is convenient to choose a different origin for the +kernel. For this reason most functions support the {origin} +parameter which gives the origin of the filter relative to its +center. For example: + +:: + + >>> a = [0, 0, 0, 1, 0, 0, 0] + >>> print correlate1d(a, [1, 1, 1], origin = -1) + [0 1 1 1 0 0 0] + +The effect is a shift of the result towards the left. This feature +will not be needed very often, but it may be useful especially for +filters that have an even size. A good example is the calculation +of backward and forward differences: + +:: + + >>> a = [0, 0, 1, 1, 1, 0, 0] + >>> print correlate1d(a, [-1, 1]) ## backward difference + [ 0 0 1 0 0 -1 0] + >>> print correlate1d(a, [-1, 1], origin = -1) ## forward difference + [ 0 1 0 0 -1 0 0] + +We could also have calculated the forward difference as follows: + +:: + + >>> print correlate1d(a, [0, -1, 1]) + [ 0 1 0 0 -1 0 0] + +however, using the origin parameter instead of a larger kernel is +more efficient. For multi-dimensional kernels {origin} can be a +number, in which case the origin is assumed to be equal along all +axes, or a sequence giving the origin along each axis. + +Since the output elements are a function of elements in the +neighborhood of the input elements, the borders of the array need +to be dealt with appropriately by providing the values outside the +borders. This is done by assuming that the arrays are extended +beyond their boundaries according certain boundary conditions. In +the functions described below, the boundary conditions can be +selected using the {mode} parameter which must be a string with the +name of the boundary condition. Following boundary conditions are +currently supported: + + {"nearest"} {Use the value at the boundary} {[1 2 3]->[1 1 2 3 3]} + {"wrap"} {Periodically replicate the array} {[1 2 3]->[3 1 2 3 1]} + {"reflect"} {Reflect the array at the boundary} + {[1 2 3]->[1 1 2 3 3]} + {"constant"} {Use a constant value, default value is 0.0} + {[1 2 3]->[0 1 2 3 0]} + + +The {"constant"} mode is special since it needs an additional +parameter to specify the constant value that should be used. + +{The easiest way to implement such boundary conditions would be to +copy the data to a larger array and extend the data at the borders +according to the boundary conditions. For large arrays and large filter +kernels, this would be very memory consuming, and the functions described +below therefore use a different approach that does not require allocating +large temporary buffers.} + +Correlation and convolution +--------------------------- + + The {correlate1d} function calculates a one-dimensional correlation + along the given axis. The lines of the array along the given axis + are correlated with the given {weights}. The {weights} parameter + must be a one-dimensional sequences of numbers. + + + The function {correlate} implements multi-dimensional correlation + of the input array with a given kernel. + + + The {convolve1d} function calculates a one-dimensional convolution + along the given axis. The lines of the array along the given axis + are convoluted with the given {weights}. The {weights} parameter + must be a one-dimensional sequences of numbers. + + {A convolution is essentially a correlation after mirroring the + kernel. As a result, the *origin* parameter behaves differently than + in the case of a correlation: the result is shifted in the opposite + directions.} + + The function {convolve} implements multi-dimensional convolution of + the input array with a given kernel. + + {A convolution is essentially a correlation after mirroring the + kernel. As a result, the *origin* parameter behaves differently than + in the case of a correlation: the results is shifted in the opposite + direction.} + +.. _ndimage_filter_functions_smoothing: + +Smoothing filters +----------------- + + + The {gaussian_filter1d} function implements a one-dimensional + Gaussian filter. The standard-deviation of the Gaussian filter is + passed through the parameter {sigma}. Setting {order}=0 corresponds + to convolution with a Gaussian kernel. An order of 1, 2, or 3 + corresponds to convolution with the first, second or third + derivatives of a Gaussian. Higher order derivatives are not + implemented. + + + The {gaussian_filter} function implements a multi-dimensional + Gaussian filter. The standard-deviations of the Gaussian filter + along each axis are passed through the parameter {sigma} as a + sequence or numbers. If {sigma} is not a sequence but a single + number, the standard deviation of the filter is equal along all + directions. The order of the filter can be specified separately for + each axis. An order of 0 corresponds to convolution with a Gaussian + kernel. An order of 1, 2, or 3 corresponds to convolution with the + first, second or third derivatives of a Gaussian. Higher order + derivatives are not implemented. The {order} parameter must be a + number, to specify the same order for all axes, or a sequence of + numbers to specify a different order for each axis. + + {The multi-dimensional filter is implemented as a sequence of + one-dimensional Gaussian filters. The intermediate arrays are stored in + the same data type as the output. Therefore, for output types with a + lower precision, the results may be imprecise because intermediate + results may be stored with insufficient precision. This can be + prevented by specifying a more precise output type.} + + + The {uniform_filter1d} function calculates a one-dimensional + uniform filter of the given {size} along the given axis. + + + The {uniform_filter} implements a multi-dimensional uniform + filter. The sizes of the uniform filter are given for each axis as + a sequence of integers by the {size} parameter. If {size} is not a + sequence, but a single number, the sizes along all axis are assumed + to be equal. + + {The multi-dimensional filter is implemented as a sequence of + one-dimensional uniform filters. The intermediate arrays are stored in + the same data type as the output. Therefore, for output types with a + lower precision, the results may be imprecise because intermediate + results may be stored with insufficient precision. This can be + prevented by specifying a + more precise output type.} + + +Filters based on order statistics +--------------------------------- + + The {minimum_filter1d} function calculates a one-dimensional + minimum filter of given {size} along the given axis. + + + The {maximum_filter1d} function calculates a one-dimensional + maximum filter of given {size} along the given axis. + + + The {minimum_filter} function calculates a multi-dimensional + minimum filter. Either the sizes of a rectangular kernel or the + footprint of the kernel must be provided. The {size} parameter, if + provided, must be a sequence of sizes or a single number in which + case the size of the filter is assumed to be equal along each axis. + The {footprint}, if provided, must be an array that defines the + shape of the kernel by its non-zero elements. + + + The {maximum_filter} function calculates a multi-dimensional + maximum filter. Either the sizes of a rectangular kernel or the + footprint of the kernel must be provided. The {size} parameter, if + provided, must be a sequence of sizes or a single number in which + case the size of the filter is assumed to be equal along each axis. + The {footprint}, if provided, must be an array that defines the + shape of the kernel by its non-zero elements. + + + The {rank_filter} function calculates a multi-dimensional rank + filter. The {rank} may be less then zero, i.e., {rank}=-1 indicates + the largest element. Either the sizes of a rectangular kernel or + the footprint of the kernel must be provided. The {size} parameter, + if provided, must be a sequence of sizes or a single number in + which case the size of the filter is assumed to be equal along each + axis. The {footprint}, if provided, must be an array that defines + the shape of the kernel by its non-zero elements. + + + The {percentile_filter} function calculates a multi-dimensional + percentile filter. The {percentile} may be less then zero, i.e., + {percentile}=-20 equals {percentile}=80. Either the sizes of a + rectangular kernel or the footprint of the kernel must be provided. + The {size} parameter, if provided, must be a sequence of sizes or a + single number in which case the size of the filter is assumed to be + equal along each axis. The {footprint}, if provided, must be an + array that defines the shape of the kernel by its non-zero + elements. + + + The {median_filter} function calculates a multi-dimensional median + filter. Either the sizes of a rectangular kernel or the footprint + of the kernel must be provided. The {size} parameter, if provided, + must be a sequence of sizes or a single number in which case the + size of the filter is assumed to be equal along each axis. The + {footprint} if provided, must be an array that defines the shape of + the kernel by its non-zero elements. + + +Derivatives +----------- + +Derivative filters can be constructed in several ways. The function +{gaussian_filter1d} described in section +:ref:`_ndimage_filter_functions_smoothing` can be used to calculate +derivatives along a given axis using the {order} parameter. Other +derivative filters are the Prewitt and Sobel filters: + + The {prewitt} function calculates a derivative along the given + axis. + + + The {sobel} function calculates a derivative along the given + axis. + + +The Laplace filter is calculated by the sum of the second +derivatives along all axes. Thus, different Laplace filters can be +constructed using different second derivative functions. Therefore +we provide a general function that takes a function argument to +calculate the second derivative along a given direction and to +construct the Laplace filter: + + The function {generic_laplace} calculates a laplace filter using + the function passed through {derivative2} to calculate second + derivatives. The function {derivative2} should have the following + signature: + + {derivative2(input, axis, output, mode, cval, \*extra_arguments, \*\*extra_keywords)} + + It should calculate the second derivative along the dimension + {axis}. If {output} is not {None} it should use that for the output + and return {None}, otherwise it should return the result. {mode}, + {cval} have the usual meaning. + + The {extra_arguments} and {extra_keywords} arguments can be used + to pass a tuple of extra arguments and a dictionary of named + arguments that are passed to {derivative2} at each call. + + For example: + + :: + + >>> def d2(input, axis, output, mode, cval): + ... return correlate1d(input, [1, -2, 1], axis, output, mode, cval, 0) + ... + >>> a = zeros((5, 5)) + >>> a[2, 2] = 1 + >>> print generic_laplace(a, d2) + [[ 0 0 0 0 0] + [ 0 0 1 0 0] + [ 0 1 -4 1 0] + [ 0 0 1 0 0] + [ 0 0 0 0 0]] + + To demonstrate the use of the {extra_arguments} argument we could + do: + + :: + + >>> def d2(input, axis, output, mode, cval, weights): + ... return correlate1d(input, weights, axis, output, mode, cval, 0,) + ... + >>> a = zeros((5, 5)) + >>> a[2, 2] = 1 + >>> print generic_laplace(a, d2, extra_arguments = ([1, -2, 1],)) + [[ 0 0 0 0 0] + [ 0 0 1 0 0] + [ 0 1 -4 1 0] + [ 0 0 1 0 0] + [ 0 0 0 0 0]] + + or: + + :: + + >>> print generic_laplace(a, d2, extra_keywords = {'weights': [1, -2, 1]}) + [[ 0 0 0 0 0] + [ 0 0 1 0 0] + [ 0 1 -4 1 0] + [ 0 0 1 0 0] + [ 0 0 0 0 0]] + + +The following two functions are implemented using +{generic_laplace} by providing appropriate functions for the +second derivative function: + + The function {laplace} calculates the Laplace using discrete + differentiation for the second derivative (i.e. convolution with + {[1, -2, 1]}). + + + The function {gaussian_laplace} calculates the Laplace using + {gaussian_filter} to calculate the second derivatives. The + standard-deviations of the Gaussian filter along each axis are + passed through the parameter {sigma} as a sequence or numbers. If + {sigma} is not a sequence but a single number, the standard + deviation of the filter is equal along all directions. + + +The gradient magnitude is defined as the square root of the sum of +the squares of the gradients in all directions. Similar to the +generic Laplace function there is a {generic_gradient_magnitude} +function that calculated the gradient magnitude of an array: + + The function {generic_gradient_magnitude} calculates a gradient + magnitude using the function passed through {derivative} to + calculate first derivatives. The function {derivative} should have + the following signature: + + {derivative(input, axis, output, mode, cval, \*extra_arguments, \*\*extra_keywords)} + + It should calculate the derivative along the dimension {axis}. If + {output} is not {None} it should use that for the output and return + {None}, otherwise it should return the result. {mode}, {cval} have + the usual meaning. + + The {extra_arguments} and {extra_keywords} arguments can be used + to pass a tuple of extra arguments and a dictionary of named + arguments that are passed to {derivative} at each call. + + For example, the {sobel} function fits the required signature: + + :: + + >>> a = zeros((5, 5)) + >>> a[2, 2] = 1 + >>> print generic_gradient_magnitude(a, sobel) + [[0 0 0 0 0] + [0 1 2 1 0] + [0 2 0 2 0] + [0 1 2 1 0] + [0 0 0 0 0]] + + See the documentation of {generic_laplace} for examples of using + the {extra_arguments} and {extra_keywords} arguments. + + +The {sobel} and {prewitt} functions fit the required signature and +can therefore directly be used with {generic_gradient_magnitude}. +The following function implements the gradient magnitude using +Gaussian derivatives: + + The function {gaussian_gradient_magnitude} calculates the + gradient magnitude using {gaussian_filter} to calculate the first + derivatives. The standard-deviations of the Gaussian filter along + each axis are passed through the parameter {sigma} as a sequence or + numbers. If {sigma} is not a sequence but a single number, the + standard deviation of the filter is equal along all directions. + + +Generic filter functions +------------------------ + +.. _ndimage_genericfilters: + +To implement filter functions, generic functions can be used that accept a +callable object that implements the filtering operation. The iteration over the +input and output arrays is handled by these generic functions, along with such +details as the implementation of the boundary conditions. Only a +callable object implementing a callback function that does the +actual filtering work must be provided. The callback function can +also be written in C and passed using a CObject (see +:ref:`_ndimage_ccallbacks` for more information). + + The {generic_filter1d} function implements a generic + one-dimensional filter function, where the actual filtering + operation must be supplied as a python function (or other callable + object). The {generic_filter1d} function iterates over the lines + of an array and calls {function} at each line. The arguments that + are passed to {function} are one-dimensional arrays of the + {tFloat64} type. The first contains the values of the current line. + It is extended at the beginning end the end, according to the + {filter_size} and {origin} arguments. The second array should be + modified in-place to provide the output values of the line. For + example consider a correlation along one dimension: + + :: + + >>> a = arange(12, shape = (3,4)) + >>> print correlate1d(a, [1, 2, 3]) + [[ 3 8 14 17] + [27 32 38 41] + [51 56 62 65]] + + The same operation can be implemented using {generic_filter1d} as + follows: + + :: + + >>> def fnc(iline, oline): + ... oline[...] = iline[:-2] + 2 * iline[1:-1] + 3 * iline[2:] + ... + >>> print generic_filter1d(a, fnc, 3) + [[ 3 8 14 17] + [27 32 38 41] + [51 56 62 65]] + + Here the origin of the kernel was (by default) assumed to be in the + middle of the filter of length 3. Therefore, each input line was + extended by one value at the beginning and at the end, before the + function was called. + + Optionally extra arguments can be defined and passed to the filter + function. The {extra_arguments} and {extra_keywords} arguments + can be used to pass a tuple of extra arguments and/or a dictionary + of named arguments that are passed to derivative at each call. For + example, we can pass the parameters of our filter as an argument: + + :: + + >>> def fnc(iline, oline, a, b): + ... oline[...] = iline[:-2] + a * iline[1:-1] + b * iline[2:] + ... + >>> print generic_filter1d(a, fnc, 3, extra_arguments = (2, 3)) + [[ 3 8 14 17] + [27 32 38 41] + [51 56 62 65]] + + or + + :: + + >>> print generic_filter1d(a, fnc, 3, extra_keywords = {'a':2, 'b':3}) + [[ 3 8 14 17] + [27 32 38 41] + [51 56 62 65]] + + + The {generic_filter} function implements a generic filter + function, where the actual filtering operation must be supplied as + a python function (or other callable object). The {generic_filter} + function iterates over the array and calls {function} at each + element. The argument of {function} is a one-dimensional array of + the {tFloat64} type, that contains the values around the current + element that are within the footprint of the filter. The function + should return a single value that can be converted to a double + precision number. For example consider a correlation: + + :: + + >>> a = arange(12, shape = (3,4)) + >>> print correlate(a, [[1, 0], [0, 3]]) + [[ 0 3 7 11] + [12 15 19 23] + [28 31 35 39]] + + The same operation can be implemented using {generic_filter} as + follows: + + :: + + >>> def fnc(buffer): + ... return (buffer * array([1, 3])).sum() + ... + >>> print generic_filter(a, fnc, footprint = [[1, 0], [0, 1]]) + [[ 0 3 7 11] + [12 15 19 23] + [28 31 35 39]] + + Here a kernel footprint was specified that contains only two + elements. Therefore the filter function receives a buffer of length + equal to two, which was multiplied with the proper weights and the + result summed. + + When calling {generic_filter}, either the sizes of a rectangular + kernel or the footprint of the kernel must be provided. The {size} + parameter, if provided, must be a sequence of sizes or a single + number in which case the size of the filter is assumed to be equal + along each axis. The {footprint}, if provided, must be an array + that defines the shape of the kernel by its non-zero elements. + + Optionally extra arguments can be defined and passed to the filter + function. The {extra_arguments} and {extra_keywords} arguments + can be used to pass a tuple of extra arguments and/or a dictionary + of named arguments that are passed to derivative at each call. For + example, we can pass the parameters of our filter as an argument: + + :: + + >>> def fnc(buffer, weights): + ... weights = asarray(weights) + ... return (buffer * weights).sum() + ... + >>> print generic_filter(a, fnc, footprint = [[1, 0], [0, 1]], extra_arguments = ([1, 3],)) + [[ 0 3 7 11] + [12 15 19 23] + [28 31 35 39]] + + or + + :: + + >>> print generic_filter(a, fnc, footprint = [[1, 0], [0, 1]], extra_keywords= {'weights': [1, 3]}) + [[ 0 3 7 11] + [12 15 19 23] + [28 31 35 39]] + + +These functions iterate over the lines or elements starting at the +last axis, i.e. the last index changest the fastest. This order of +iteration is garantueed for the case that it is important to adapt +the filter dependening on spatial location. Here is an example of +using a class that implements the filter and keeps track of the +current coordinates while iterating. It performs the same filter +operation as described above for {generic_filter}, but +additionally prints the current coordinates: + +:: + + >>> a = arange(12, shape = (3,4)) + >>> + >>> class fnc_class: + ... def __init__(self, shape): + ... # store the shape: + ... self.shape = shape + ... # initialize the coordinates: + ... self.coordinates = [0] * len(shape) + ... + ... def filter(self, buffer): + ... result = (buffer * array([1, 3])).sum() + ... print self.coordinates + ... # calculate the next coordinates: + ... axes = range(len(self.shape)) + ... axes.reverse() + ... for jj in axes: + ... if self.coordinates[jj] < self.shape[jj] - 1: + ... self.coordinates[jj] += 1 + ... break + ... else: + ... self.coordinates[jj] = 0 + ... return result + ... + >>> fnc = fnc_class(shape = (3,4)) + >>> print generic_filter(a, fnc.filter, footprint = [[1, 0], [0, 1]]) + [0, 0] + [0, 1] + [0, 2] + [0, 3] + [1, 0] + [1, 1] + [1, 2] + [1, 3] + [2, 0] + [2, 1] + [2, 2] + [2, 3] + [[ 0 3 7 11] + [12 15 19 23] + [28 31 35 39]] + +For the {generic_filter1d} function the same approach works, +except that this function does not iterate over the axis that is +being filtered. The example for {generic_filte1d} then becomes +this: + +:: + + >>> a = arange(12, shape = (3,4)) + >>> + >>> class fnc1d_class: + ... def __init__(self, shape, axis = -1): + ... # store the filter axis: + ... self.axis = axis + ... # store the shape: + ... self.shape = shape + ... # initialize the coordinates: + ... self.coordinates = [0] * len(shape) + ... + ... def filter(self, iline, oline): + ... oline[...] = iline[:-2] + 2 * iline[1:-1] + 3 * iline[2:] + ... print self.coordinates + ... # calculate the next coordinates: + ... axes = range(len(self.shape)) + ... # skip the filter axis: + ... del axes[self.axis] + ... axes.reverse() + ... for jj in axes: + ... if self.coordinates[jj] < self.shape[jj] - 1: + ... self.coordinates[jj] += 1 + ... break + ... else: + ... self.coordinates[jj] = 0 + ... + >>> fnc = fnc1d_class(shape = (3,4)) + >>> print generic_filter1d(a, fnc.filter, 3) + [0, 0] + [1, 0] + [2, 0] + [[ 3 8 14 17] + [27 32 38 41] + [51 56 62 65]] + +Fourier domain filters +====================== + +The functions described in this section perform filtering +operations in the Fourier domain. Thus, the input array of such a +function should be compatible with an inverse Fourier transform +function, such as the functions from the {numarray.fft} module. We +therefore have to deal with arrays that may be the result of a real +or a complex Fourier transform. In the case of a real Fourier +transform only half of the of the symmetric complex transform is +stored. Additionally, it needs to be known what the length of the +axis was that was transformed by the real fft. The functions +described here provide a parameter {n} that in the case of a real +transform must be equal to the length of the real transform axis +before transformation. If this parameter is less than zero, it is +assumed that the input array was the result of a complex Fourier +transform. The parameter {axis} can be used to indicate along which +axis the real transform was executed. + + The {fourier_shift} function multiplies the input array with the + multi-dimensional Fourier transform of a shift operation for the + given shift. The {shift} parameter is a sequences of shifts for + each dimension, or a single value for all dimensions. + + + The {fourier_gaussian} function multiplies the input array with + the multi-dimensional Fourier transform of a Gaussian filter with + given standard-deviations {sigma}. The {sigma} parameter is a + sequences of values for each dimension, or a single value for all + dimensions. + + + The {fourier_uniform} function multiplies the input array with the + multi-dimensional Fourier transform of a uniform filter with given + sizes {size}. The {size} parameter is a sequences of values for + each dimension, or a single value for all dimensions. + + + The {fourier_ellipsoid} function multiplies the input array with + the multi-dimensional Fourier transform of a elliptically shaped + filter with given sizes {size}. The {size} parameter is a sequences + of values for each dimension, or a single value for all dimensions. + {This function is + only implemented for dimensions 1, 2, and 3.} + + +Interpolation functions +======================= + +This section describes various interpolation functions that are +based on B-spline theory. A good introduction to B-splines can be +found in: M. Unser, "Splines: A Perfect Fit for Signal and Image +Processing," IEEE Signal Processing Magazine, vol. 16, no. 6, pp. +22-38, November 1999. {Spline pre-filters} Interpolation using +splines of an order larger than 1 requires a pre- filtering step. +The interpolation functions described in section +:ref:`_ndimage_interpolation` apply pre-filtering by calling +{spline_filter}, but they can be instructed not to do this by +setting the {prefilter} keyword equal to {False}. This is useful if +more than one interpolation operation is done on the same array. In +this case it is more efficient to do the pre-filtering only once +and use a prefiltered array as the input of the interpolation +functions. The following two functions implement the +pre-filtering: + + The {spline_filter1d} function calculates a one-dimensional spline + filter along the given axis. An output array can optionally be + provided. The order of the spline must be larger then 1 and less + than 6. + + + The {spline_filter} function calculates a multi-dimensional spline + filter. + + {The multi-dimensional filter is implemented as a sequence of + one-dimensional spline filters. The intermediate arrays are stored in + the same data type as the output. Therefore, if an output + with a limited precision is requested, the results may be imprecise + because intermediate results may be stored with insufficient precision. + This can be prevented by specifying a output type of high precision.} + + +Interpolation functions +----------------------- + +.. _ndimage_interpolation: + +Following functions all employ spline interpolation to effect some type of +geometric transformation of the input array. This requires a mapping of the +output coordinates to the input coordinates, and therefore the possibility +arises that input values outside the boundaries are needed. This problem is +solved in the same way as described in section :ref:`_ndimage_filter_functions` +for the multi-dimensional filter functions. Therefore these functions all +support a {mode} parameter that determines how the boundaries are handled, and +a {cval} parameter that gives a constant value in case that the {'constant'} +mode is used. + + The {geometric_transform} function applies an arbitrary geometric + transform to the input. The given {mapping} function is called at + each point in the output to find the corresponding coordinates in + the input. {mapping} must be a callable object that accepts a tuple + of length equal to the output array rank and returns the + corresponding input coordinates as a tuple of length equal to the + input array rank. The output shape and output type can optionally + be provided. If not given they are equal to the input shape and + type. + + For example: + + :: + + >>> a = arange(12, shape=(4,3), type = Float64) + >>> def shift_func(output_coordinates): + ... return (output_coordinates[0] - 0.5, output_coordinates[1] - 0.5) + ... + >>> print geometric_transform(a, shift_func) + [[ 0. 0. 0. ] + [ 0. 1.3625 2.7375] + [ 0. 4.8125 6.1875] + [ 0. 8.2625 9.6375]] + + Optionally extra arguments can be defined and passed to the filter + function. The {extra_arguments} and {extra_keywords} arguments + can be used to pass a tuple of extra arguments and/or a dictionary + of named arguments that are passed to derivative at each call. For + example, we can pass the shifts in our example as arguments: + + :: + + >>> def shift_func(output_coordinates, s0, s1): + ... return (output_coordinates[0] - s0, output_coordinates[1] - s1) + ... + >>> print geometric_transform(a, shift_func, extra_arguments = (0.5, 0.5)) + [[ 0. 0. 0. ] + [ 0. 1.3625 2.7375] + [ 0. 4.8125 6.1875] + [ 0. 8.2625 9.6375]] + + or + + :: + + >>> print geometric_transform(a, shift_func, extra_keywords = {'s0': 0.5, 's1': 0.5}) + [[ 0. 0. 0. ] + [ 0. 1.3625 2.7375] + [ 0. 4.8125 6.1875] + [ 0. 8.2625 9.6375]] + + {The mapping function can also be written in C and passed using a CObject. See :ref:`_ndimage_ccallbacks` for more information.} + + + The function {map_coordinates} applies an arbitrary coordinate + transformation using the given array of coordinates. The shape of + the output is derived from that of the coordinate array by dropping + the first axis. The parameter {coordinates} is used to find for + each point in the output the corresponding coordinates in the + input. The values of {coordinates} along the first axis are the + coordinates in the input array at which the output value is found. + (See also the numarray {coordinates} function.) Since the + coordinates may be non- integer coordinates, the value of the input + at these coordinates is determined by spline interpolation of the + requested order. Here is an example that interpolates a 2D array at + (0.5, 0.5) and (1, 2): + + :: + + >>> a = arange(12, shape=(4,3), type = numarray.Float64) + >>> print a + [[ 0. 1. 2.] + [ 3. 4. 5.] + [ 6. 7. 8.] + [ 9. 10. 11.]] + >>> print map_coordinates(a, [[0.5, 2], [0.5, 1]]) + [ 1.3625 7. ] + + + The {affine_transform} function applies an affine transformation + to the input array. The given transformation {matrix} and {offset} + are used to find for each point in the output the corresponding + coordinates in the input. The value of the input at the calculated + coordinates is determined by spline interpolation of the requested + order. The transformation {matrix} must be two-dimensional or can + also be given as a one-dimensional sequence or array. In the latter + case, it is assumed that the matrix is diagonal. A more efficient + interpolation algorithm is then applied that exploits the + separability of the problem. The output shape and output type can + optionally be provided. If not given they are equal to the input + shape and type. + + + The {shift} function returns a shifted version of the input, using + spline interpolation of the requested {order}. + + + The {zoom} function returns a rescaled version of the input, using + spline interpolation of the requested {order}. + + + The {rotate} function returns the input array rotated in the plane + defined by the two axes given by the parameter {axes}, using spline + interpolation of the requested {order}. The angle must be given in + degrees. If {reshape} is true, then the size of the output array is + adapted to contain the rotated input. + + +Binary morphology +================= + +.. _ndimage_binary_morphology: + + The {generate_binary_structure} functions generates a binary + structuring element for use in binary morphology operations. The + {rank} of the structure must be provided. The size of the structure + that is returned is equal to three in each direction. The value of + each element is equal to one if the square of the Euclidean + distance from the element to the center is less or equal to + {connectivity}. For instance, two dimensional 4-connected and + 8-connected structures are generated as follows: + + :: + + >>> print generate_binary_structure(2, 1) + [[0 1 0] + [1 1 1] + [0 1 0]] + >>> print generate_binary_structure(2, 2) + [[1 1 1] + [1 1 1] + [1 1 1]] + + +Most binary morphology functions can be expressed in terms of the +basic operations erosion and dilation: + + The {binary_erosion} function implements binary erosion of arrays + of arbitrary rank with the given structuring element. The origin + parameter controls the placement of the structuring element as + described in section :ref:`_ndimage_filter_functions`. If no + structuring element is provided, an element with connectivity equal + to one is generated using {generate_binary_structure}. The + {border_value} parameter gives the value of the array outside + boundaries. The erosion is repeated {iterations} times. If + {iterations} is less than one, the erosion is repeated until the + result does not change anymore. If a {mask} array is given, only + those elements with a true value at the corresponding mask element + are modified at each iteration. + + + The {binary_dilation} function implements binary dilation of + arrays of arbitrary rank with the given structuring element. The + origin parameter controls the placement of the structuring element + as described in section :ref:`_ndimage_filter_functions`. If no + structuring element is provided, an element with connectivity equal + to one is generated using {generate_binary_structure}. The + {border_value} parameter gives the value of the array outside + boundaries. The dilation is repeated {iterations} times. If + {iterations} is less than one, the dilation is repeated until the + result does not change anymore. If a {mask} array is given, only + those elements with a true value at the corresponding mask element + are modified at each iteration. + + Here is an example of using {binary_dilation} to find all elements + that touch the border, by repeatedly dilating an empty array from + the border using the data array as the mask: + + :: + + >>> struct = array([[0, 1, 0], [1, 1, 1], [0, 1, 0]]) + >>> a = array([[1,0,0,0,0], [1,1,0,1,0], [0,0,1,1,0], [0,0,0,0,0]]) + >>> print a + [[1 0 0 0 0] + [1 1 0 1 0] + [0 0 1 1 0] + [0 0 0 0 0]] + >>> print binary_dilation(zeros(a.shape), struct, -1, a, border_value=1) + [[1 0 0 0 0] + [1 1 0 0 0] + [0 0 0 0 0] + [0 0 0 0 0]] + + +The {binary_erosion} and {binary_dilation} functions both have an +{iterations} parameter which allows the erosion or dilation to be +repeated a number of times. Repeating an erosion or a dilation with +a given structure {n} times is equivalent to an erosion or a +dilation with a structure that is {n-1} times dilated with itself. +A function is provided that allows the calculation of a structure +that is dilated a number of times with itself: + + The {iterate_structure} function returns a structure by dilation + of the input structure {iteration} - 1 times with itself. For + instance: + + :: + + >>> struct = generate_binary_structure(2, 1) + >>> print struct + [[0 1 0] + [1 1 1] + [0 1 0]] + >>> print iterate_structure(struct, 2) + [[0 0 1 0 0] + [0 1 1 1 0] + [1 1 1 1 1] + [0 1 1 1 0] + [0 0 1 0 0]] + + If the origin of the original structure is equal to 0, then it is + also equal to 0 for the iterated structure. If not, the origin must + also be adapted if the equivalent of the {iterations} erosions or + dilations must be achieved with the iterated structure. The adapted + origin is simply obtained by multiplying with the number of + iterations. For convenience the {iterate_structure} also returns + the adapted origin if the {origin} parameter is not {None}: + + :: + + >>> print iterate_structure(struct, 2, -1) + (array([[0, 0, 1, 0, 0], + [0, 1, 1, 1, 0], + [1, 1, 1, 1, 1], + [0, 1, 1, 1, 0], + [0, 0, 1, 0, 0]], type=Bool), [-2, -2]) + + +Other morphology operations can be defined in terms of erosion and +d dilation. Following functions provide a few of these operations +for convenience: + + The {binary_opening} function implements binary opening of arrays + of arbitrary rank with the given structuring element. Binary + opening is equivalent to a binary erosion followed by a binary + dilation with the same structuring element. The origin parameter + controls the placement of the structuring element as described in + section :ref:`_ndimage_filter_functions`. If no structuring element is + provided, an element with connectivity equal to one is generated + using {generate_binary_structure}. The {iterations} parameter + gives the number of erosions that is performed followed by the same + number of dilations. + + + The {binary_closing} function implements binary closing of arrays + of arbitrary rank with the given structuring element. Binary + closing is equivalent to a binary dilation followed by a binary + erosion with the same structuring element. The origin parameter + controls the placement of the structuring element as described in + section :ref:`_ndimage_filter_functions`. If no structuring element is + provided, an element with connectivity equal to one is generated + using {generate_binary_structure}. The {iterations} parameter + gives the number of dilations that is performed followed by the + same number of erosions. + + + The {binary_fill_holes} function is used to close holes in + objects in a binary image, where the structure defines the + connectivity of the holes. The origin parameter controls the + placement of the structuring element as described in section + :ref:`_ndimage_filter_functions`. If no structuring element is + provided, an element with connectivity equal to one is generated + using {generate_binary_structure}. + + + The {binary_hit_or_miss} function implements a binary + hit-or-miss transform of arrays of arbitrary rank with the given + structuring elements. The hit-or-miss transform is calculated by + erosion of the input with the first structure, erosion of the + logical *not* of the input with the second structure, followed by + the logical *and* of these two erosions. The origin parameters + control the placement of the structuring elements as described in + section :ref:`_ndimage_filter_functions`. If {origin2} equals {None} it + is set equal to the {origin1} parameter. If the first structuring + element is not provided, a structuring element with connectivity + equal to one is generated using {generate_binary_structure}, if + {structure2} is not provided, it is set equal to the logical *not* + of {structure1}. + + +Grey-scale morphology +===================== + +.. _ndimage_grey_morphology: + + + +Grey-scale morphology operations are the equivalents of binary +morphology operations that operate on arrays with arbitrary values. +Below we describe the grey-scale equivalents of erosion, dilation, +opening and closing. These operations are implemented in a similar +fashion as the filters described in section +:ref:`_ndimage_filter_functions`, and we refer to this section for the +description of filter kernels and footprints, and the handling of +array borders. The grey-scale morphology operations optionally take +a {structure} parameter that gives the values of the structuring +element. If this parameter is not given the structuring element is +assumed to be flat with a value equal to zero. The shape of the +structure can optionally be defined by the {footprint} parameter. +If this parameter is not given, the structure is assumed to be +rectangular, with sizes equal to the dimensions of the {structure} +array, or by the {size} parameter if {structure} is not given. The +{size} parameter is only used if both {structure} and {footprint} +are not given, in which case the structuring element is assumed to +be rectangular and flat with the dimensions given by {size}. The +{size} parameter, if provided, must be a sequence of sizes or a +single number in which case the size of the filter is assumed to be +equal along each axis. The {footprint} parameter, if provided, must +be an array that defines the shape of the kernel by its non-zero +elements. + +Similar to binary erosion and dilation there are operations for +grey-scale erosion and dilation: + + The {grey_erosion} function calculates a multi-dimensional grey- + scale erosion. + + + The {grey_dilation} function calculates a multi-dimensional grey- + scale dilation. + + +Grey-scale opening and closing operations can be defined similar to +their binary counterparts: + + The {grey_opening} function implements grey-scale opening of + arrays of arbitrary rank. Grey-scale opening is equivalent to a + grey-scale erosion followed by a grey-scale dilation. + + + The {grey_closing} function implements grey-scale closing of + arrays of arbitrary rank. Grey-scale opening is equivalent to a + grey-scale dilation followed by a grey-scale erosion. + + + The {morphological_gradient} function implements a grey-scale + morphological gradient of arrays of arbitrary rank. The grey-scale + morphological gradient is equal to the difference of a grey-scale + dilation and a grey-scale erosion. + + + The {morphological_laplace} function implements a grey-scale + morphological laplace of arrays of arbitrary rank. The grey-scale + morphological laplace is equal to the sum of a grey-scale dilation + and a grey-scale erosion minus twice the input. + + + The {white_tophat} function implements a white top-hat filter of + arrays of arbitrary rank. The white top-hat is equal to the + difference of the input and a grey-scale opening. + + + The {black_tophat} function implements a black top-hat filter of + arrays of arbitrary rank. The black top-hat is equal to the + difference of the a grey-scale closing and the input. + + +Distance transforms +=================== + +.. _ndimage_distance_transforms: + +Distance transforms are used to +calculate the minimum distance from each element of an object to +the background. The following functions implement distance +transforms for three different distance metrics: Euclidean, City +Block, and Chessboard distances. + + The function {distance_transform_cdt} uses a chamfer type + algorithm to calculate the distance transform of the input, by + replacing each object element (defined by values larger than zero) + with the shortest distance to the background (all non-object + elements). The structure determines the type of chamfering that is + done. If the structure is equal to 'cityblock' a structure is + generated using {generate_binary_structure} with a squared + distance equal to 1. If the structure is equal to 'chessboard', a + structure is generated using {generate_binary_structure} with a + squared distance equal to the rank of the array. These choices + correspond to the common interpretations of the cityblock and the + chessboard distancemetrics in two dimensions. + + In addition to the distance transform, the feature transform can be + calculated. In this case the index of the closest background + element is returned along the first axis of the result. The + {return_distances}, and {return_indices} flags can be used to + indicate if the distance transform, the feature transform, or both + must be returned. + + The {distances} and {indices} arguments can be used to give + optional output arrays that must be of the correct size and type + (both {Int32}). + + The basics of the algorithm used to implement this function is + described in: G. Borgefors, "Distance transformations in arbitrary + dimensions.", Computer Vision, Graphics, and Image Processing, + 27:321-345, 1984. + + + The function {distance_transform_edt} calculates the exact + euclidean distance transform of the input, by replacing each object + element (defined by values larger than zero) with the shortest + euclidean distance to the background (all non-object elements). + + In addition to the distance transform, the feature transform can be + calculated. In this case the index of the closest background + element is returned along the first axis of the result. The + {return_distances}, and {return_indices} flags can be used to + indicate if the distance transform, the feature transform, or both + must be returned. + + Optionally the sampling along each axis can be given by the + {sampling} parameter which should be a sequence of length equal to + the input rank, or a single number in which the sampling is assumed + to be equal along all axes. + + The {distances} and {indices} arguments can be used to give + optional output arrays that must be of the correct size and type + ({Float64} and {Int32}). + + The algorithm used to implement this function is described in: C. + R. Maurer, Jr., R. Qi, and V. Raghavan, "A linear time algorithm + for computing exact euclidean distance transforms of binary images + in arbitrary dimensions. IEEE Trans. PAMI 25, 265-270, 2003. + + + The function {distance_transform_bf} uses a brute-force algorithm + to calculate the distance transform of the input, by replacing each + object element (defined by values larger than zero) with the + shortest distance to the background (all non-object elements). The + metric must be one of {"euclidean"}, {"cityblock"}, or + {"chessboard"}. + + In addition to the distance transform, the feature transform can be + calculated. In this case the index of the closest background + element is returned along the first axis of the result. The + {return_distances}, and {return_indices} flags can be used to + indicate if the distance transform, the feature transform, or both + must be returned. + + Optionally the sampling along each axis can be given by the + {sampling} parameter which should be a sequence of length equal to + the input rank, or a single number in which the sampling is assumed + to be equal along all axes. This parameter is only used in the case + of the euclidean distance transform. + + The {distances} and {indices} arguments can be used to give + optional output arrays that must be of the correct size and type + ({Float64} and {Int32}). + + {This function uses a slow brute-force algorithm, the function + :func:`distance_transform_cdt` can be used to more efficiently + calculate cityblock and chessboard distance transforms. The function + :func:`distance_transform_edt` can be used to more efficiently + calculate the exact euclidean distance transform.} + + +Segmentation and labeling +========================= + +Segmentation is the process of separating objects of interest from +the background. The most simple approach is probably intensity +thresholding, which is easily done with {numarray} functions: + +:: + + >>> a = array([[1,2,2,1,1,0], + ... [0,2,3,1,2,0], + ... [1,1,1,3,3,2], + ... [1,1,1,1,2,1]]) + >>> print where(a > 1, 1, 0) + [[0 1 1 0 0 0] + [0 1 1 0 1 0] + [0 0 0 1 1 1] + [0 0 0 0 1 0]] + +The result is a binary image, in which the individual objects still +need to be identified and labeled. The function {label} generates +an array where each object is assigned a unique number: + + The {label} function generates an array where the objects in the + input are labeled with an integer index. It returns a tuple + consisting of the array of object labels and the number of objects + found, unless the {output} parameter is given, in which case only + the number of objects is returned. The connectivity of the objects + is defined by a structuring element. For instance, in two + dimensions using a four-connected structuring element gives: + + :: + + >>> a = array([[0,1,1,0,0,0],[0,1,1,0,1,0],[0,0,0,1,1,1],[0,0,0,0,1,0]]) + >>> s = [[0, 1, 0], [1,1,1], [0,1,0]] + >>> print label(a, s) + (array([[0, 1, 1, 0, 0, 0], + [0, 1, 1, 0, 2, 0], + [0, 0, 0, 2, 2, 2], + [0, 0, 0, 0, 2, 0]]), 2) + + These two objects are not connected because there is no way in + which we can place the structuring element such that it overlaps + with both objects. However, an 8-connected structuring element + results in only a single object: + + :: + + >>> a = array([[0,1,1,0,0,0],[0,1,1,0,1,0],[0,0,0,1,1,1],[0,0,0,0,1,0]]) + >>> s = [[1,1,1], [1,1,1], [1,1,1]] + >>> print label(a, s)[0] + [[0 1 1 0 0 0] + [0 1 1 0 1 0] + [0 0 0 1 1 1] + [0 0 0 0 1 0]] + + If no structuring element is provided, one is generated by calling + {generate_binary_structure} (see section :ref:`_ndimage_morphology`) + using a connectivity of one (which in 2D is the 4-connected + structure of the first example). The input can be of any type, any + value not equal to zero is taken to be part of an object. This is + useful if you need to 're-label' an array of object indices, for + instance after removing unwanted objects. Just apply the label + function again to the index array. For instance: + + :: + + >>> l, n = label([1, 0, 1, 0, 1]) + >>> print l + [1 0 2 0 3] + >>> l = where(l != 2, l, 0) + >>> print l + [1 0 0 0 3] + >>> print label(l)[0] + [1 0 0 0 2] + + {The structuring element used by :func:`label` is assumed to be + symmetric.} + + +There is a large number of other approaches for segmentation, for +instance from an estimation of the borders of the objects that can +be obtained for instance by derivative filters. One such an +approach is watershed segmentation. The function {watershed_ift} +generates an array where each object is assigned a unique label, +from an array that localizes the object borders, generated for +instance by a gradient magnitude filter. It uses an array +containing initial markers for the objects: + + The {watershed_ift} function applies a watershed from markers + algorithm, using an Iterative Forest Transform, as described in: P. + Felkel, R. Wegenkittl, and M. Bruckschwaiger, "Implementation and + Complexity of the Watershed-from-Markers Algorithm Computed as a + Minimal Cost Forest.", Eurographics 2001, pp. C:26-35. + + The inputs of this function are the array to which the transform is + applied, and an array of markers that designate the objects by a + unique label, where any non-zero value is a marker. For instance: + + :: + + >>> input = array([[0, 0, 0, 0, 0, 0, 0], + ... [0, 1, 1, 1, 1, 1, 0], + ... [0, 1, 0, 0, 0, 1, 0], + ... [0, 1, 0, 0, 0, 1, 0], + ... [0, 1, 0, 0, 0, 1, 0], + ... [0, 1, 1, 1, 1, 1, 0], + ... [0, 0, 0, 0, 0, 0, 0]], numarray.UInt8) + >>> markers = array([[1, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 2, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0]], numarray.Int8) + >>> print watershed_ift(input, markers) + [[1 1 1 1 1 1 1] + [1 1 2 2 2 1 1] + [1 2 2 2 2 2 1] + [1 2 2 2 2 2 1] + [1 2 2 2 2 2 1] + [1 1 2 2 2 1 1] + [1 1 1 1 1 1 1]] + + Here two markers were used to designate an object (marker=2) and + the background (marker=1). The order in which these are processed + is arbitrary: moving the marker for the background to the lower + right corner of the array yields a different result: + + :: + + >>> markers = array([[0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 2, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 1]], numarray.Int8) + >>> print watershed_ift(input, markers) + [[1 1 1 1 1 1 1] + [1 1 1 1 1 1 1] + [1 1 2 2 2 1 1] + [1 1 2 2 2 1 1] + [1 1 2 2 2 1 1] + [1 1 1 1 1 1 1] + [1 1 1 1 1 1 1]] + + The result is that the object (marker=2) is smaller because the + second marker was processed earlier. This may not be the desired + effect if the first marker was supposed to designate a background + object. Therefore {watershed_ift} treats markers with a negative + value explicitly as background markers and processes them after the + normal markers. For instance, replacing the first marker by a + negative marker gives a result similar to the first example: + + :: + + >>> markers = array([[0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 2, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, 0], + ... [0, 0, 0, 0, 0, 0, -1]], numarray.Int8) + >>> print watershed_ift(input, markers) + [[-1 -1 -1 -1 -1 -1 -1] + [-1 -1 2 2 2 -1 -1] + [-1 2 2 2 2 2 -1] + [-1 2 2 2 2 2 -1] + [-1 2 2 2 2 2 -1] + [-1 -1 2 2 2 -1 -1] + [-1 -1 -1 -1 -1 -1 -1]] + + The connectivity of the objects is defined by a structuring + element. If no structuring element is provided, one is generated by + calling {generate_binary_structure} (see section + :ref:`_ndimage_morphology`) using a connectivity of one (which in 2D is + a 4-connected structure.) For example, using an 8-connected + structure with the last example yields a different object: + + :: + + >>> print watershed_ift(input, markers, + ... structure = [[1,1,1], [1,1,1], [1,1,1]]) + [[-1 -1 -1 -1 -1 -1 -1] + [-1 2 2 2 2 2 -1] + [-1 2 2 2 2 2 -1] + [-1 2 2 2 2 2 -1] + [-1 2 2 2 2 2 -1] + [-1 2 2 2 2 2 -1] + [-1 -1 -1 -1 -1 -1 -1]] + + {The implementation of :func:`watershed_ift` limits the data types + of the input to \\constant{UInt8} and \\constant{UInt16}.} + + +Object measurements +=================== + +Given an array of labeled objects, the properties of the individual +objects can be measured. The {find_objects} function can be used +to generate a list of slices that for each object, give the +smallest sub-array that fully contains the object: + + The {find_objects} finds all objects in a labeled array and + returns a list of slices that correspond to the smallest regions in + the array that contains the object. For instance: + + :: + + >>> a = array([[0,1,1,0,0,0],[0,1,1,0,1,0],[0,0,0,1,1,1],[0,0,0,0,1,0]]) + >>> l, n = label(a) + >>> f = find_objects(l) + >>> print a[f[0]] + [[1 1] + [1 1]] + >>> print a[f[1]] + [[0 1 0] + [1 1 1] + [0 1 0]] + + {find_objects} returns slices for all objects, unless the + {max_label} parameter is larger then zero, in which case only the + first {max_label} objects are returned. If an index is missing in + the {label} array, {None} is return instead of a slice. For + example: + + :: + + >>> print find_objects([1, 0, 3, 4], max_label = 3) + [(slice(0, 1, None),), None, (slice(2, 3, None),)] + + +The list of slices generated by {find_objects} is useful to find +the position and dimensions of the objects in the array, but can +also be used to perform measurements on the individual objects. Say +we want to find the sum of the intensities of an object in image: + +:: + + >>> image = arange(4*6,shape=(4,6)) + >>> mask = array([[0,1,1,0,0,0],[0,1,1,0,1,0],[0,0,0,1,1,1],[0,0,0,0,1,0]]) + >>> labels = label(mask)[0] + >>> slices = find_objects(labels) + +Then we can calculate the sum of the elements in the second +object: + +:: + + >>> print where(labels[slices[1]] == 2, image[slices[1]], 0).sum() + 80 + +That is however not particularly efficient, and may also be more +complicated for other types of measurements. Therefore a few +measurements functions are defined that accept the array of object +labels and the index of the object to be measured. For instance +calculating the sum of the intensities can be done by: + +:: + + >>> print sum(image, labels, 2) + 80.0 + +For large arrays and small objects it is more efficient to call the +measurement functions after slicing the array: + +:: + + >>> print sum(image[slices[1]], labels[slices[1]], 2) + 80.0 + +Alternatively, we can do the measurements for a number of labels +with a single function call, returning a list of results. For +instance, to measure the sum of the values of the background and +the second object in our example we give a list of labels: + +:: + + >>> print sum(image, labels, [0, 2]) + [178.0, 80.0] + +The measurement functions described below all support the {index} +parameter to indicate which object(s) should be measured. The +default value of {index} is {None}. This indicates that all +elements where the label is larger than zero should be treated as a +single object and measured. Thus, in this case the {labels} array +is treated as a mask defined by the elements that are larger than +zero. If {index} is a number or a sequence of numbers it gives the +labels of the objects that are measured. If {index} is a sequence, +a list of the results is returned. Functions that return more than +one result, return their result as a tuple if {index} is a single +number, or as a tuple of lists, if {index} is a sequence. + + The {sum} function calculates the sum of the elements of the object + with label(s) given by {index}, using the {labels} array for the + object labels. If {index} is {None}, all elements with a non-zero + label value are treated as a single object. If {label} is {None}, + all elements of {input} are used in the calculation. + + + The {mean} function calculates the mean of the elements of the + object with label(s) given by {index}, using the {labels} array for + the object labels. If {index} is {None}, all elements with a + non-zero label value are treated as a single object. If {label} is + {None}, all elements of {input} are used in the calculation. + + + The {variance} function calculates the variance of the elements of + the object with label(s) given by {index}, using the {labels} array + for the object labels. If {index} is {None}, all elements with a + non-zero label value are treated as a single object. If {label} is + {None}, all elements of {input} are used in the calculation. + + + The {standard_deviation} function calculates the standard + deviation of the elements of the object with label(s) given by + {index}, using the {labels} array for the object labels. If {index} + is {None}, all elements with a non-zero label value are treated as + a single object. If {label} is {None}, all elements of {input} are + used in the calculation. + + + The {minimum} function calculates the minimum of the elements of + the object with label(s) given by {index}, using the {labels} array + for the object labels. If {index} is {None}, all elements with a + non-zero label value are treated as a single object. If {label} is + {None}, all elements of {input} are used in the calculation. + + + The {maximum} function calculates the maximum of the elements of + the object with label(s) given by {index}, using the {labels} array + for the object labels. If {index} is {None}, all elements with a + non-zero label value are treated as a single object. If {label} is + {None}, all elements of {input} are used in the calculation. + + + The {minimum_position} function calculates the position of the + minimum of the elements of the object with label(s) given by + {index}, using the {labels} array for the object labels. If {index} + is {None}, all elements with a non-zero label value are treated as + a single object. If {label} is {None}, all elements of {input} are + used in the calculation. + + + The {maximum_position} function calculates the position of the + maximum of the elements of the object with label(s) given by + {index}, using the {labels} array for the object labels. If {index} + is {None}, all elements with a non-zero label value are treated as + a single object. If {label} is {None}, all elements of {input} are + used in the calculation. + + + The {extrema} function calculates the minimum, the maximum, and + their positions, of the elements of the object with label(s) given + by {index}, using the {labels} array for the object labels. If + {index} is {None}, all elements with a non-zero label value are + treated as a single object. If {label} is {None}, all elements of + {input} are used in the calculation. The result is a tuple giving + the minimum, the maximum, the position of the mininum and the + postition of the maximum. The result is the same as a tuple formed + by the results of the functions {minimum}, {maximum}, + {minimum_position}, and {maximum_position} that are described + above. + + + The {center_of_mass} function calculates the center of mass of + the of the object with label(s) given by {index}, using the + {labels} array for the object labels. If {index} is {None}, all + elements with a non-zero label value are treated as a single + object. If {label} is {None}, all elements of {input} are used in + the calculation. + + + The {histogram} function calculates a histogram of the of the + object with label(s) given by {index}, using the {labels} array for + the object labels. If {index} is {None}, all elements with a + non-zero label value are treated as a single object. If {label} is + {None}, all elements of {input} are used in the calculation. + Histograms are defined by their minimum ({min}), maximum ({max}) + and the number of bins ({bins}). They are returned as + one-dimensional arrays of type Int32. + + +Extending {nd_image} in C +============================ + +.. _ndimage_ccallbacks: + +{C callback functions} A few functions in the {numarray.nd_image} take a call-back argument. This can be a python function, but also a CObject containing a pointer to a C function. To use this feature, you must write your own C extension that defines the function, and define a python function that +returns a CObject containing a pointer to this function. + +An example of a function that supports this is +{geometric_transform} (see section :ref:`_ndimage_interpolation`). +You can pass it a python callable object that defines a mapping +from all output coordinates to corresponding coordinates in the +input array. This mapping function can also be a C function, which +generally will be much more efficient, since the overhead of +calling a python function at each element is avoided. + +For example to implement a simple shift function we define the +following function: + +:: + + static int + _shift_function(int *output_coordinates, double* input_coordinates, + int output_rank, int input_rank, void *callback_data) + { + int ii; + /* get the shift from the callback data pointer: */ + double shift = *(double*)callback_data; + /* calculate the coordinates: */ + for(ii = 0; ii < irank; ii++) + icoor[ii] = ocoor[ii] - shift; + /* return OK status: */ + return 1; + } + +This function is called at every element of the output array, +passing the current coordinates in the {output_coordinates} array. +On return, the {input_coordinates} array must contain the +coordinates at which the input is interpolated. The ranks of the +input and output array are passed through {output_rank} and +{input_rank}. The value of the shift is passed through the +{callback_data} argument, which is a pointer to void. The function +returns an error status, in this case always 1, since no error can +occur. + +A pointer to this function and a pointer to the shift value must be +passed to {geometric_transform}. Both are passed by a single +CObject which is created by the following python extension +function: + +:: + + static PyObject * + py_shift_function(PyObject *obj, PyObject *args) + { + double shift = 0.0; + if (!PyArg_ParseTuple(args, "d", &shift)) { + PyErr_SetString(PyExc_RuntimeError, "invalid parameters"); + return NULL; + } else { + /* assign the shift to a dynamically allocated location: */ + double *cdata = (double*)malloc(sizeof(double)); + *cdata = shift; + /* wrap function and callback_data in a CObject: */ + return PyCObject_FromVoidPtrAndDesc(_shift_function, cdata, + _destructor); + } + } + +The value of the shift is obtained and then assigned to a +dynamically allocated memory location. Both this data pointer and +the function pointer are then wrapped in a CObject, which is +returned. Additionally, a pointer to a destructor function is +given, that will free the memory we allocated for the shift value +when the CObject is destroyed. This destructor is very simple: + +:: + + static void + _destructor(void* cobject, void *cdata) + { + if (cdata) + free(cdata); + } + +To use these functions, an extension module is build: + +:: + + static PyMethodDef methods[] = { + {"shift_function", (PyCFunction)py_shift_function, METH_VARARGS, ""}, + {NULL, NULL, 0, NULL} + }; + + void + initexample(void) + { + Py_InitModule("example", methods); + } + +This extension can then be used in Python, for example: + +:: + + >>> import example + >>> array = arange(12, shape=(4,3), type = Float64) + >>> fnc = example.shift_function(0.5) + >>> print geometric_transform(array, fnc) + [[ 0. 0. 0. ] + [ 0. 1.3625 2.7375] + [ 0. 4.8125 6.1875] + [ 0. 8.2625 9.6375]] + +C Callback functions for use with {nd_image} functions must all +be written according to this scheme. The next section lists the +{nd_image} functions that acccept a C callback function and +gives the prototype of the callback function. + +Functions that support C callback functions +------------------------------------------- + +The {nd_image} functions that support C callback functions are +described here. Obviously, the prototype of the function that is +provided to these functions must match exactly that what they +expect. Therefore we give here the prototypes of the callback +functions. All these callback functions accept a void +{callback_data} pointer that must be wrapped in a CObject using +the Python {PyCObject_FromVoidPtrAndDesc} function, which can also +accept a pointer to a destructor function to free any memory +allocated for {callback_data}. If {callback_data} is not needed, +{PyCObject_FromVoidPtr} may be used instead. The callback +functions must return an integer error status that is equal to zero +if something went wrong, or 1 otherwise. If an error occurs, you +should normally set the python error status with an informative +message before returning, otherwise, a default error message is set +by the calling function. + +The function {generic_filter} (see section +:ref:`_ndimage_genericfilters`) accepts a callback function with the +following prototype: + + The calling function iterates over the elements of the input and + output arrays, calling the callback function at each element. The + elements within the footprint of the filter at the current element + are passed through the {buffer} parameter, and the number of + elements within the footprint through {filter_size}. The + calculated valued should be returned in the {return_value} + argument. + + +The function {generic_filter1d} (see section +:ref:`_ndimage_genericfilters`) accepts a callback function with the +following prototype: + + The calling function iterates over the lines of the input and + output arrays, calling the callback function at each line. The + current line is extended according to the border conditions set by + the calling function, and the result is copied into the array that + is passed through the {input_line} array. The length of the input + line (after extension) is passed through {input_length}. The + callback function should apply the 1D filter and store the result + in the array passed through {output_line}. The length of the + output line is passed through {output_length}. + + +The function {geometric_transform} (see section +:ref:`_ndimage_interpolation`) expects a function with the following +prototype: + + The calling function iterates over the elements of the output + array, calling the callback function at each element. The + coordinates of the current output element are passed through + {output_coordinates}. The callback function must return the + coordinates at which the input must be interpolated in + {input_coordinates}. The rank of the input and output arrays are + given by {input_rank} and {output_rank} respectively. + + + From scipy-svn at scipy.org Fri Dec 19 12:55:51 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Fri, 19 Dec 2008 11:55:51 -0600 (CST) Subject: [Scipy-svn] r5278 - in trunk/doc: . frontpage/_templates Message-ID: <20081219175551.D12DFC8410A@scipy.org> Author: ptvirtan Date: 2008-12-19 11:55:32 -0600 (Fri, 19 Dec 2008) New Revision: 5278 Modified: trunk/doc/Makefile trunk/doc/frontpage/_templates/indexcontent.html Log: docs: put CHM files in a zip, to work around http://support.microsoft.com/kb/902225/ Modified: trunk/doc/Makefile =================================================================== --- trunk/doc/Makefile 2008-12-18 23:49:30 UTC (rev 5277) +++ trunk/doc/Makefile 2008-12-19 17:55:32 UTC (rev 5278) @@ -44,7 +44,7 @@ perl -pi -e 's#^\s*(
  • SciPy.*?Reference Guide.*?»
  • )\s*$$#
  • Numpy and Scipy Documentation »
  • $$1#;' build/dist/*.html build/dist/*/*.html build/dist/*/*/*.html (cd build/html && zip -9qr ../dist/scipy-html.zip .) cp build/latex/scipy*.pdf build/dist - -cp build/htmlhelp/scipy.chm build/dist + -zip build/dist/scipy-chm.zip build/htmlhelp/scipy.chm cd build/dist && tar czf ../dist.tar.gz * chmod ug=rwX,o=rX -R build/dist find build/dist -type d -print0 | xargs -0r chmod g+s Modified: trunk/doc/frontpage/_templates/indexcontent.html =================================================================== --- trunk/doc/frontpage/_templates/indexcontent.html 2008-12-18 23:49:30 UTC (rev 5277) +++ trunk/doc/frontpage/_templates/indexcontent.html 2008-12-19 17:55:32 UTC (rev 5278) @@ -19,7 +19,7 @@ From scipy-svn at scipy.org Fri Dec 19 15:34:05 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Fri, 19 Dec 2008 14:34:05 -0600 (CST) Subject: [Scipy-svn] r5279 - in trunk/scipy/signal: . tests Message-ID: <20081219203405.4F032C7C023@scipy.org> Author: jarrod.millman Date: 2008-12-19 14:34:02 -0600 (Fri, 19 Dec 2008) New Revision: 5279 Modified: trunk/scipy/signal/medianfilter.c trunk/scipy/signal/tests/test_signaltools.py Log: Applying patch from Ray Jones to medianfilter to remove code based on Numerical Recipes. It includes the following: * new quickselect (from scratch) in medianfilter.c * new macros for {f,d,b}_medfilt2 in medianfilter.c * modified test for medfilt and medfilt2 (larger array, non-square filter). Modified: trunk/scipy/signal/medianfilter.c =================================================================== --- trunk/scipy/signal/medianfilter.c 2008-12-19 17:55:32 UTC (rev 5278) +++ trunk/scipy/signal/medianfilter.c 2008-12-19 20:34:02 UTC (rev 5279) @@ -1,311 +1,127 @@ /*--------------------------------------------------------------------*/ -/* - * This Quickselect routine is based on the algorithm described in - * "Numerical recipies in C", Second Edition, - * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 - */ - #include "Python.h" #define NO_IMPORT_ARRAY #include "numpy/noprefix.h" + +/* defined below */ void f_medfilt2(float*,float*,intp*,intp*); void d_medfilt2(double*,double*,intp*,intp*); void b_medfilt2(unsigned char*,unsigned char*,intp*,intp*); extern char *check_malloc (int); -#define ELEM_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; } -float f_quick_select(float arr[], int n) -{ - int low, high ; - int median; - int middle, ll, hh; +/* The QUICK_SELECT routine is based on Hoare's Quickselect algorithm, + * with unrolled recursion. + * Author: Thouis R. Jones, 2008 + */ - low = 0 ; high = n-1 ; median = (low + high) / 2; - for (;;) { - if (high <= low) /* One element only */ - return arr[median] ; +#define ELEM_SWAP(t, a, x, y) {register t temp = (a)[x]; (a)[x] = (a)[y]; (a)[y] = temp;} +#define FIRST_LOWEST(x, y, z) (((x) < (y)) && ((x) < (z))) +#define FIRST_HIGHEST(x, y, z) (((x) > (y)) && ((x) > (z))) +#define LOWEST_IDX(a, x, y) (((a)[x] < (a)[y]) ? (x) : (y)) +#define HIGHEST_IDX(a, x, y) (((a)[x] > (a)[y]) ? (x) : (y)) - if (high == low + 1) { /* Two elements only */ - if (arr[low] > arr[high]) - ELEM_SWAP(arr[low], arr[high]) ; - return arr[median] ; - } +/* if (l is index of lowest) {return lower of mid,hi} else if (l is index of highest) {return higher of mid,hi} else return l */ +#define MEDIAN_IDX(a, l, m, h) (FIRST_LOWEST((a)[l], (a)[m], (a)[h]) ? LOWEST_IDX(a, m, h) : (FIRST_HIGHEST((a)[l], (a)[m], (a)[h]) ? HIGHEST_IDX(a, m, h) : (l))) - /* Find median of low, middle and high items; swap into position low */ - middle = (low + high) / 2; - if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; - if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; - if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; - - /* Swap low item (now in position middle) into position (low+1) */ - ELEM_SWAP(arr[middle], arr[low+1]) ; - - /* Nibble from each end towards middle, swapping items when stuck */ - ll = low + 1; - hh = high; - for (;;) { - do ll++; while (arr[low] > arr[ll]) ; - do hh--; while (arr[hh] > arr[low]) ; - - if (hh < ll) - break; - - ELEM_SWAP(arr[ll], arr[hh]) ; - } - - /* Swap middle item (in position low) back into correct position */ - ELEM_SWAP(arr[low], arr[hh]) ; - - /* Re-set active partition */ - if (hh <= median) - low = ll; - if (hh >= median) - high = hh - 1; - } +#define QUICK_SELECT(NAME, TYPE) \ +TYPE NAME(TYPE arr[], int n) \ +{ \ + int lo, hi, mid, md; \ + int median_idx; \ + int ll, hh; \ + TYPE piv; \ + \ + lo = 0; hi = n-1; \ + median_idx = (n - 1) / 2; /* lower of middle values for even-length arrays */ \ + \ + while (1) { \ + if ((hi - lo) < 2) { \ + if (arr[hi] < arr[lo]) ELEM_SWAP(TYPE, arr, lo, hi); \ + return arr[median_idx]; \ + } \ + \ + mid = (hi + lo) / 2; \ + /* put the median of lo,mid,hi at position lo - this will be the pivot */ \ + md = MEDIAN_IDX(arr, lo, mid, hi); \ + ELEM_SWAP(TYPE, arr, lo, md); \ + \ + /* Nibble from each end towards middle, swapping misordered items */ \ + piv = arr[lo]; \ + for (ll = lo+1, hh = hi;; ll++, hh--) { \ + while (arr[ll] < piv) ll++; \ + while (arr[hh] > piv) hh--; \ + if (hh < ll) break; \ + ELEM_SWAP(TYPE, arr, ll, hh); \ + } \ + /* move pivot to top of lower partition */ \ + ELEM_SWAP(TYPE, arr, hh, lo); \ + /* set lo, hi for new range to search */ \ + if (hh < median_idx) /* search upper partition */ \ + lo = hh+1; \ + else if (hh > median_idx) /* search lower partition */ \ + hi = hh-1; \ + else \ + return piv; \ + } \ } -#undef ELEM_SWAP - -#define ELEM_SWAP(a,b) { register double t=(a);(a)=(b);(b)=t; } - -double d_quick_select(double arr[], int n) -{ - int low, high ; - int median; - int middle, ll, hh; - - low = 0 ; high = n-1 ; median = (low + high) / 2; - for (;;) { - if (high <= low) /* One element only */ - return arr[median] ; - - if (high == low + 1) { /* Two elements only */ - if (arr[low] > arr[high]) - ELEM_SWAP(arr[low], arr[high]) ; - return arr[median] ; - } - - /* Find median of low, middle and high items; swap into position low */ - middle = (low + high) / 2; - if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; - if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; - if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; - - /* Swap low item (now in position middle) into position (low+1) */ - ELEM_SWAP(arr[middle], arr[low+1]) ; - - /* Nibble from each end towards middle, swapping items when stuck */ - ll = low + 1; - hh = high; - for (;;) { - do ll++; while (arr[low] > arr[ll]) ; - do hh--; while (arr[hh] > arr[low]) ; - - if (hh < ll) - break; - - ELEM_SWAP(arr[ll], arr[hh]) ; - } - - /* Swap middle item (in position low) back into correct position */ - ELEM_SWAP(arr[low], arr[hh]) ; - - /* Re-set active partition */ - if (hh <= median) - low = ll; - if (hh >= median) - high = hh - 1; - } -} - -#undef ELEM_SWAP - -#define ELEM_SWAP(a,b) { register unsigned char t=(a);(a)=(b);(b)=t; } - -unsigned char b_quick_select(unsigned char arr[], int n) -{ - int low, high ; - int median; - int middle, ll, hh; - - low = 0 ; high = n-1 ; median = (low + high) / 2; - for (;;) { - if (high <= low) /* One element only */ - return arr[median] ; - - if (high == low + 1) { /* Two elements only */ - if (arr[low] > arr[high]) - ELEM_SWAP(arr[low], arr[high]) ; - return arr[median] ; - } - - /* Find median of low, middle and high items; swap into position low */ - middle = (low + high) / 2; - if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; - if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; - if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; - - /* Swap low item (now in position middle) into position (low+1) */ - ELEM_SWAP(arr[middle], arr[low+1]) ; - - /* Nibble from each end towards middle, swapping items when stuck */ - ll = low + 1; - hh = high; - for (;;) { - do ll++; while (arr[low] > arr[ll]) ; - do hh--; while (arr[hh] > arr[low]) ; - - if (hh < ll) - break; - - ELEM_SWAP(arr[ll], arr[hh]) ; - } - - /* Swap middle item (in position low) back into correct position */ - ELEM_SWAP(arr[low], arr[hh]) ; - - /* Re-set active partition */ - if (hh <= median) - low = ll; - if (hh >= median) - high = hh - 1; - } -} - -#undef ELEM_SWAP - /* 2-D median filter with zero-padding on edges. */ -void d_medfilt2(double* in, double* out, intp* Nwin, intp* Ns) -{ - int nx, ny, hN[2]; - int pre_x, pre_y, pos_x, pos_y; - int subx, suby, k, totN; - double *myvals, *fptr1, *fptr2, *ptr1, *ptr2; - - totN = Nwin[0] * Nwin[1]; - myvals = (double *) check_malloc( totN * sizeof(double)); - - hN[0] = Nwin[0] >> 1; - hN[1] = Nwin[1] >> 1; - ptr1 = in; - fptr1 = out; - for (ny = 0; ny < Ns[0]; ny++) - for (nx = 0; nx < Ns[1]; nx++) { - pre_x = hN[1]; - pre_y = hN[0]; - pos_x = hN[1]; - pos_y = hN[0]; - if (nx < hN[1]) pre_x = nx; - if (nx >= Ns[1] - hN[1]) pos_x = Ns[1] - nx - 1; - if (ny < hN[0]) pre_y = ny; - if (ny >= Ns[0] - hN[0]) pos_y = Ns[0] - ny - 1; - fptr2 = myvals; - ptr2 = ptr1 - pre_x - pre_y*Ns[1]; - for (suby = -pre_y; suby <= pos_y; suby++) { - for (subx = -pre_x; subx <= pos_x; subx++) - *fptr2++ = *ptr2++; - ptr2 += Ns[1] - (pre_x + pos_x + 1); - } - ptr1++; - - /* Zero pad */ - for (k = (pre_x + pos_x + 1)*(pre_y + pos_y + 1); k < totN; k++) - *fptr2++ = 0.0; - - /* *fptr1++ = median(myvals,totN); */ - *fptr1++ = d_quick_select(myvals,totN); - } +#define MEDIAN_FILTER_2D(NAME, TYPE, SELECT) \ +void NAME(TYPE* in, TYPE* out, intp* Nwin, intp* Ns) \ +{ \ + int nx, ny, hN[2]; \ + int pre_x, pre_y, pos_x, pos_y; \ + int subx, suby, k, totN; \ + TYPE *myvals, *fptr1, *fptr2, *ptr1, *ptr2; \ + \ + totN = Nwin[0] * Nwin[1]; \ + myvals = (TYPE *) check_malloc( totN * sizeof(TYPE)); \ + \ + hN[0] = Nwin[0] >> 1; \ + hN[1] = Nwin[1] >> 1; \ + ptr1 = in; \ + fptr1 = out; \ + for (ny = 0; ny < Ns[0]; ny++) \ + for (nx = 0; nx < Ns[1]; nx++) { \ + pre_x = hN[1]; \ + pre_y = hN[0]; \ + pos_x = hN[1]; \ + pos_y = hN[0]; \ + if (nx < hN[1]) pre_x = nx; \ + if (nx >= Ns[1] - hN[1]) pos_x = Ns[1] - nx - 1; \ + if (ny < hN[0]) pre_y = ny; \ + if (ny >= Ns[0] - hN[0]) pos_y = Ns[0] - ny - 1; \ + fptr2 = myvals; \ + ptr2 = ptr1 - pre_x - pre_y*Ns[1]; \ + for (suby = -pre_y; suby <= pos_y; suby++) { \ + for (subx = -pre_x; subx <= pos_x; subx++) \ + *fptr2++ = *ptr2++; \ + ptr2 += Ns[1] - (pre_x + pos_x + 1); \ + } \ + ptr1++; \ + \ + /* Zero pad */ \ + for (k = (pre_x + pos_x + 1)*(pre_y + pos_y + 1); k < totN; k++) \ + *fptr2++ = 0.0; \ + \ + /* *fptr1++ = median(myvals,totN); */ \ + *fptr1++ = SELECT(myvals,totN); \ + } \ + free(myvals); \ } -/* 2-D median filter with zero-padding on edges. */ -void f_medfilt2(float* in, float* out, intp* Nwin, intp* Ns) -{ - int nx, ny, hN[2]; - int pre_x, pre_y, pos_x, pos_y; - int subx, suby, k, totN; - float *myvals, *fptr1, *fptr2, *ptr1, *ptr2; +/* define quick_select for floats, doubles, and unsigned characters */ +QUICK_SELECT(f_quick_select, float) +QUICK_SELECT(d_quick_select, double) +QUICK_SELECT(b_quick_select, unsigned char) - totN = Nwin[0] * Nwin[1]; - myvals = (float *) check_malloc( totN * sizeof(float)); - - hN[0] = Nwin[0] >> 1; - hN[1] = Nwin[1] >> 1; - ptr1 = in; - fptr1 = out; - for (ny = 0; ny < Ns[0]; ny++) - for (nx = 0; nx < Ns[1]; nx++) { - pre_x = hN[1]; - pre_y = hN[0]; - pos_x = hN[1]; - pos_y = hN[0]; - if (nx < hN[1]) pre_x = nx; - if (nx >= Ns[1] - hN[1]) pos_x = Ns[1] - nx - 1; - if (ny < hN[0]) pre_y = ny; - if (ny >= Ns[0] - hN[0]) pos_y = Ns[0] - ny - 1; - fptr2 = myvals; - ptr2 = ptr1 - pre_x - pre_y*Ns[1]; - for (suby = -pre_y; suby <= pos_y; suby++) { - for (subx = -pre_x; subx <= pos_x; subx++) - *fptr2++ = *ptr2++; - ptr2 += Ns[1] - (pre_x + pos_x + 1); - } - ptr1++; - - /* Zero pad */ - for (k = (pre_x + pos_x + 1)*(pre_y + pos_y + 1); k < totN; k++) - *fptr2++ = 0.0; - - /* *fptr1++ = median(myvals,totN); */ - *fptr1++ = f_quick_select(myvals,totN); - } -} - - -/* 2-D median filter with zero-padding on edges. */ -void b_medfilt2(unsigned char *in, unsigned char *out, intp* Nwin, intp* Ns) -{ - int nx, ny, hN[2]; - int pre_x, pre_y, pos_x, pos_y; - int subx, suby, k, totN; - unsigned char *myvals, *fptr1, *fptr2, *ptr1, *ptr2; - - totN = Nwin[0] * Nwin[1]; - myvals = (unsigned char *) check_malloc( totN * sizeof(unsigned char)); - - hN[0] = Nwin[0] >> 1; - hN[1] = Nwin[1] >> 1; - ptr1 = in; - fptr1 = out; - for (ny = 0; ny < Ns[0]; ny++) - for (nx = 0; nx < Ns[1]; nx++) { - pre_x = hN[1]; - pre_y = hN[0]; - pos_x = hN[1]; - pos_y = hN[0]; - if (nx < hN[1]) pre_x = nx; - if (nx >= Ns[1] - hN[1]) pos_x = Ns[1] - nx - 1; - if (ny < hN[0]) pre_y = ny; - if (ny >= Ns[0] - hN[0]) pos_y = Ns[0] - ny - 1; - fptr2 = myvals; - ptr2 = ptr1 - pre_x - pre_y*Ns[1]; - for (suby = -pre_y; suby <= pos_y; suby++) { - for (subx = -pre_x; subx <= pos_x; subx++) - *fptr2++ = *ptr2++; - ptr2 += Ns[1] - (pre_x + pos_x + 1); - } - ptr1++; - - /* Zero pad */ - for (k = (pre_x + pos_x + 1)*(pre_y + pos_y + 1); k < totN; k++) - *fptr2++ = 0.0; - - /* *fptr1++ = median(myvals,totN); */ - *fptr1++ = b_quick_select(myvals,totN); - } -} +/* define medfilt for floats, doubles, and unsigned characters */ +MEDIAN_FILTER_2D(f_medfilt2, float, f_quick_select) +MEDIAN_FILTER_2D(d_medfilt2, double, d_quick_select) +MEDIAN_FILTER_2D(b_medfilt2, unsigned char, b_quick_select) Modified: trunk/scipy/signal/tests/test_signaltools.py =================================================================== --- trunk/scipy/signal/tests/test_signaltools.py 2008-12-19 17:55:32 UTC (rev 5278) +++ trunk/scipy/signal/tests/test_signaltools.py 2008-12-19 20:34:02 UTC (rev 5279) @@ -28,9 +28,30 @@ class TestMedFilt(TestCase): def test_basic(self): - f = [[3,4,5],[2,3,4],[1,2,5]] - d = signal.medfilt(f) - assert_array_equal(d, [[0,3,0],[2,3,3],[0,2,0]]) + f = [[50, 50, 50, 50, 50, 92, 18, 27, 65, 46], + [50, 50, 50, 50, 50, 0, 72, 77, 68, 66], + [50, 50, 50, 50, 50, 46, 47, 19, 64, 77], + [50, 50, 50, 50, 50, 42, 15, 29, 95, 35], + [50, 50, 50, 50, 50, 46, 34, 9, 21, 66], + [70, 97, 28, 68, 78, 77, 61, 58, 71, 42], + [64, 53, 44, 29, 68, 32, 19, 68, 24, 84], + [ 3, 33, 53, 67, 1, 78, 74, 55, 12, 83], + [ 7, 11, 46, 70, 60, 47, 24, 43, 61, 26], + [32, 61, 88, 7, 39, 4, 92, 64, 45, 61]] + + d = signal.medfilt(f, [7, 3]) + e = signal.medfilt2d(np.array(f, np.float), [7, 3]) + assert_array_equal(d, [[ 0, 50, 50, 50, 42, 15, 15, 18, 27, 0], + [ 0, 50, 50, 50, 50, 42, 19, 21, 29, 0], + [50, 50, 50, 50, 50, 47, 34, 34, 46, 35], + [50, 50, 50, 50, 50, 50, 42, 47, 64, 42], + [50, 50, 50, 50, 50, 50, 46, 55, 64, 35], + [33, 50, 50, 50, 50, 47, 46, 43, 55, 26], + [32, 50, 50, 50, 50, 47, 46, 45, 55, 26], + [ 7, 46, 50, 50, 47, 46, 46, 43, 45, 21], + [ 0, 32, 33, 39, 32, 32, 43, 43, 43, 0], + [ 0, 7, 11, 7, 4, 4, 19, 19, 24, 0]]) + assert_array_equal(d, e) class TestWiener(TestCase): def test_basic(self): From scipy-svn at scipy.org Sat Dec 20 01:53:25 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 20 Dec 2008 00:53:25 -0600 (CST) Subject: [Scipy-svn] r5280 - in trunk/scipy/stats: . tests Message-ID: <20081220065325.74655C7C043@scipy.org> Author: josef Date: 2008-12-20 00:53:22 -0600 (Sat, 20 Dec 2008) New Revision: 5280 Modified: trunk/scipy/stats/stats.py trunk/scipy/stats/tests/test_stats.py Log: ttest_rel: some cleanup, rewrite main formula Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-19 20:34:02 UTC (rev 5279) +++ trunk/scipy/stats/stats.py 2008-12-20 06:53:22 UTC (rev 5280) @@ -1950,7 +1950,6 @@ zerodivproblem = svar == 0 t = (x1-x2)/np.sqrt(svar*(1.0/n1 + 1.0/n2)) # N-D COMPUTATION HERE!!!!!! t = np.where(zerodivproblem, 1.0, t) # replace NaN t-values with 1.0 - #probs = betai(0.5*df,0.5,float(df)/(df+t*t)) probs = distributions.t.sf(np.abs(t),df)*2 if not np.isscalar(t): @@ -2017,13 +2016,11 @@ df = float(n-1) d = (a-b).astype('d') - #denom is just var(d)/df - denom = np.sqrt((n*np.add.reduce(d*d,axis) - np.add.reduce(d,axis)**2) /df) + #denom is just sqrt(var(d)/df) + denom = np.sqrt(np.var(d,axis,ddof=1)/float(n)) zerodivproblem = denom == 0 - t = np.add.reduce(d, axis) / denom # N-D COMPUTATION HERE!!!!!! + t = np.mean(d, axis) / denom t = np.where(zerodivproblem, 1.0, t) # replace NaN t-values with 1.0 - t = np.where(zerodivproblem, 1.0, t) # replace NaN t-values with 1.0 - #probs = betai(0.5*df,0.5,float(df)/(df+t*t)) probs = distributions.t.sf(np.abs(t),df)*2 if not np.isscalar(t): probs = np.reshape(probs, t.shape) Modified: trunk/scipy/stats/tests/test_stats.py =================================================================== --- trunk/scipy/stats/tests/test_stats.py 2008-12-19 20:34:02 UTC (rev 5279) +++ trunk/scipy/stats/tests/test_stats.py 2008-12-20 06:53:22 UTC (rev 5280) @@ -1054,5 +1054,24 @@ np.linspace(1,100,110)+20-0.1)), np.array((0.20818181818181825, 0.017981441789762638))) +def test_ttest_rel(): + #regression test + tr,pr = 0.81248591389165692, 0.41846234511362157 + tpr = ([tr,-tr],[pr,pr]) + + rvs1 = np.linspace(1,100,100) + rvs2 = np.linspace(1.01,99.989,100) + rvs1_2D = np.array([np.linspace(1,100,100), np.linspace(1.01,99.989,100)]) + rvs2_2D = np.array([np.linspace(1.01,99.989,100), np.linspace(1,100,100)]) + + t,p = stats.ttest_rel(rvs1, rvs2, axis=0) + assert_array_almost_equal([t,p],(tr,pr)) + t,p = stats.ttest_rel(rvs1_2D.T, rvs2_2D.T, axis=0) + assert_array_almost_equal([t,p],tpr) + t,p = stats.ttest_rel(rvs1_2D, rvs2_2D, axis=1) + assert_array_almost_equal([t,p],tpr) + + + if __name__ == "__main__": run_module_suite() From scipy-svn at scipy.org Sat Dec 20 06:05:18 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 20 Dec 2008 05:05:18 -0600 (CST) Subject: [Scipy-svn] r5281 - trunk/doc/source/tutorial Message-ID: <20081220110518.0487AC7C042@scipy.org> Author: david.warde-farley Date: 2008-12-20 05:05:15 -0600 (Sat, 20 Dec 2008) New Revision: 5281 Modified: trunk/doc/source/tutorial/ndimage.rst Log: Huge fixer-upper. All module functions prefixed with :func: (is this correct?). All parameters enclosed in \*param\* (seemed like the closest thing in the Sphinx documentation that I could find. Tables and sectional cross-references fixed. Modified: trunk/doc/source/tutorial/ndimage.rst =================================================================== --- trunk/doc/source/tutorial/ndimage.rst 2008-12-20 06:53:22 UTC (rev 5280) +++ trunk/doc/source/tutorial/ndimage.rst 2008-12-20 11:05:15 UTC (rev 5281) @@ -1,42 +1,44 @@ -Multi-dimensional image processing -================================== +Multi-dimensional image processing (:mod:`ndimage`) +========================================================= -{Peter Verveer} {verveer at users.sourceforge.net} -{Multidimensional image analysis functions} +.. moduleauthor:: Peter Verveer -.. _ndimage_introduction: +.. currentmodule:: scipy.ndimage + +.. _ndimage-introduction: + Introduction -============ +------------ Image processing and analysis are generally seen as operations on two-dimensional arrays of values. There are however a number of fields where images of higher dimensionality must be analyzed. Good examples of these are medical imaging and biological imaging. -{numarray} is suited very well for this type of applications due -its inherent multi-dimensional nature. The {numarray.nd_image} +:mod:`numarray` is suited very well for this type of applications due +its inherent multi-dimensional nature. The :mod:`scipy.ndimage` packages provides a number of general image processing and analysis functions that are designed to operate with arrays of arbitrary dimensionality. The packages currently includes functions for linear and non-linear filtering, binary morphology, B-spline interpolation, and object measurements. -.. _ndimage_properties_shared_by_all_functions: +.. _ndimage-properties-shared-by-all-functions: Properties shared by all functions -================================== +---------------------------------- All functions share some common properties. Notably, all functions -allow the specification of an output array with the {output} +allow the specification of an output array with the *output* argument. With this argument you can specify an array that will be changed in-place with the result with the operation. In this case -the result is not returned. Usually, using the {output} argument is +the result is not returned. Usually, using the *output* argument is more efficient, since an existing array is used to store the result. The type of arrays returned is dependent on the type of operation, but it is in most cases equal to the type of the input. If, -however, the {output} argument is used, the type of the result is +however, the *output* argument is used, the type of the result is equal to the type of the specified output argument. If no output argument is given, it is still possible to specify what the result of the output should be. This is done by simply assigning the @@ -51,15 +53,15 @@ {In previous versions of :mod:`scipy.ndimage`, some functions accepted the *output_type* argument to achieve the same effect. This argument is still supported, but its use will generate an deprecation warning. In a future version all instances of this argument will be removed. The preferred way to specify an output type, is by using the *output* argument, either by specifying an output array of the desired type, or by specifying the type of the output that is to be returned.} +.. _ndimage-filter-functions: + Filter functions -================ +---------------- -.. _ndimage_filter_functions: - The functions described in this section all perform some type of spatial filtering of the the input array: the elements in the output are some function of the values in the neighborhood of the corresponding input element. We refer to this neighborhood of elements as the filter kernel, which is often rectangular in shape but may also have an arbitrary footprint. Many of the functions described below allow you to define the footprint -of the kernel, by passing a mask through the {footprint} parameter. +of the kernel, by passing a mask through the *footprint* parameter. For example a cross shaped kernel can be defined as follows: :: @@ -84,7 +86,7 @@ [0 0 1 1 1 0 0] Sometimes it is convenient to choose a different origin for the -kernel. For this reason most functions support the {origin} +kernel. For this reason most functions support the *origin* parameter which gives the origin of the filter relative to its center. For example: @@ -115,7 +117,7 @@ [ 0 1 0 0 -1 0 0] however, using the origin parameter instead of a larger kernel is -more efficient. For multi-dimensional kernels {origin} can be a +more efficient. For multi-dimensional kernels *origin* can be a number, in which case the origin is assumed to be equal along all axes, or a sequence giving the origin along each axis. @@ -125,18 +127,18 @@ borders. This is done by assuming that the arrays are extended beyond their boundaries according certain boundary conditions. In the functions described below, the boundary conditions can be -selected using the {mode} parameter which must be a string with the +selected using the *mode* parameter which must be a string with the name of the boundary condition. Following boundary conditions are currently supported: - {"nearest"} {Use the value at the boundary} {[1 2 3]->[1 1 2 3 3]} - {"wrap"} {Periodically replicate the array} {[1 2 3]->[3 1 2 3 1]} - {"reflect"} {Reflect the array at the boundary} - {[1 2 3]->[1 1 2 3 3]} - {"constant"} {Use a constant value, default value is 0.0} - {[1 2 3]->[0 1 2 3 0]} + ========== ==================================== ==================== + ------------------------------------------------------------------------ + "nearest" Use the value at the boundary [1 2 3]->[1 1 2 3 3] + "wrap" Periodically replicate the array [1 2 3]->[3 1 2 3 1] + "reflect" Reflect the array at the boundary [1 2 3]->[1 1 2 3 3] + "constant" Use a constant value, default is 0.0 [1 2 3]->[0 1 2 3 0] + ========== ==================================== ==================== - The {"constant"} mode is special since it needs an additional parameter to specify the constant value that should be used. @@ -150,19 +152,19 @@ Correlation and convolution --------------------------- - The {correlate1d} function calculates a one-dimensional correlation + The :func:`correlate1d` function calculates a one-dimensional correlation along the given axis. The lines of the array along the given axis - are correlated with the given {weights}. The {weights} parameter + are correlated with the given *weights*. The *weights* parameter must be a one-dimensional sequences of numbers. - The function {correlate} implements multi-dimensional correlation + The function :func:`correlate` implements multi-dimensional correlation of the input array with a given kernel. - The {convolve1d} function calculates a one-dimensional convolution + The :func:`convolve1d` function calculates a one-dimensional convolution along the given axis. The lines of the array along the given axis - are convoluted with the given {weights}. The {weights} parameter + are convoluted with the given *weights*. The *weights* parameter must be a one-dimensional sequences of numbers. {A convolution is essentially a correlation after mirroring the @@ -170,7 +172,7 @@ in the case of a correlation: the result is shifted in the opposite directions.} - The function {convolve} implements multi-dimensional convolution of + The function :func:`convolve` implements multi-dimensional convolution of the input array with a given kernel. {A convolution is essentially a correlation after mirroring the @@ -178,31 +180,31 @@ in the case of a correlation: the results is shifted in the opposite direction.} -.. _ndimage_filter_functions_smoothing: +.. _ndimage-filter-functions-smoothing: Smoothing filters ----------------- - The {gaussian_filter1d} function implements a one-dimensional + The :func:`gaussian_filter1d` function implements a one-dimensional Gaussian filter. The standard-deviation of the Gaussian filter is - passed through the parameter {sigma}. Setting {order}=0 corresponds + passed through the parameter *sigma*. Setting *order* = 0 corresponds to convolution with a Gaussian kernel. An order of 1, 2, or 3 corresponds to convolution with the first, second or third derivatives of a Gaussian. Higher order derivatives are not implemented. - The {gaussian_filter} function implements a multi-dimensional + The :func:`gaussian_filter` function implements a multi-dimensional Gaussian filter. The standard-deviations of the Gaussian filter - along each axis are passed through the parameter {sigma} as a - sequence or numbers. If {sigma} is not a sequence but a single + along each axis are passed through the parameter *sigma* as a + sequence or numbers. If *sigma* is not a sequence but a single number, the standard deviation of the filter is equal along all directions. The order of the filter can be specified separately for each axis. An order of 0 corresponds to convolution with a Gaussian kernel. An order of 1, 2, or 3 corresponds to convolution with the first, second or third derivatives of a Gaussian. Higher order - derivatives are not implemented. The {order} parameter must be a + derivatives are not implemented. The *order* parameter must be a number, to specify the same order for all axes, or a sequence of numbers to specify a different order for each axis. @@ -214,13 +216,13 @@ prevented by specifying a more precise output type.} - The {uniform_filter1d} function calculates a one-dimensional - uniform filter of the given {size} along the given axis. + The :func:`uniform_filter1d` function calculates a one-dimensional + uniform filter of the given *size* along the given axis. - The {uniform_filter} implements a multi-dimensional uniform + The :func:`uniform_filter` implements a multi-dimensional uniform filter. The sizes of the uniform filter are given for each axis as - a sequence of integers by the {size} parameter. If {size} is not a + a sequence of integers by the *size* parameter. If *size* is not a sequence, but a single number, the sizes along all axis are assumed to be equal. @@ -236,59 +238,59 @@ Filters based on order statistics --------------------------------- - The {minimum_filter1d} function calculates a one-dimensional - minimum filter of given {size} along the given axis. + The :func:`minimum_filter1d` function calculates a one-dimensional + minimum filter of given *size* along the given axis. - The {maximum_filter1d} function calculates a one-dimensional - maximum filter of given {size} along the given axis. + The :func:`maximum_filter1d` function calculates a one-dimensional + maximum filter of given *size* along the given axis. - The {minimum_filter} function calculates a multi-dimensional + The :func:`minimum_filter` function calculates a multi-dimensional minimum filter. Either the sizes of a rectangular kernel or the - footprint of the kernel must be provided. The {size} parameter, if + footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be equal along each axis. - The {footprint}, if provided, must be an array that defines the + The *footprint*, if provided, must be an array that defines the shape of the kernel by its non-zero elements. - The {maximum_filter} function calculates a multi-dimensional + The :func:`maximum_filter` function calculates a multi-dimensional maximum filter. Either the sizes of a rectangular kernel or the - footprint of the kernel must be provided. The {size} parameter, if + footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be equal along each axis. - The {footprint}, if provided, must be an array that defines the + The *footprint*, if provided, must be an array that defines the shape of the kernel by its non-zero elements. - The {rank_filter} function calculates a multi-dimensional rank - filter. The {rank} may be less then zero, i.e., {rank}=-1 indicates + The :func:`rank_filter` function calculates a multi-dimensional rank + filter. The *rank* may be less then zero, i.e., *rank* =-1 indicates the largest element. Either the sizes of a rectangular kernel or - the footprint of the kernel must be provided. The {size} parameter, + the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be equal along each - axis. The {footprint}, if provided, must be an array that defines + axis. The *footprint*, if provided, must be an array that defines the shape of the kernel by its non-zero elements. - The {percentile_filter} function calculates a multi-dimensional - percentile filter. The {percentile} may be less then zero, i.e., - {percentile}=-20 equals {percentile}=80. Either the sizes of a + The :func:`percentile_filter` function calculates a multi-dimensional + percentile filter. The *percentile* may be less then zero, i.e., + *percentile* =-20 equals *percentile* =80. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. - The {size} parameter, if provided, must be a sequence of sizes or a + The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be - equal along each axis. The {footprint}, if provided, must be an + equal along each axis. The *footprint*, if provided, must be an array that defines the shape of the kernel by its non-zero elements. - The {median_filter} function calculates a multi-dimensional median + The :func:`median_filter` function calculates a multi-dimensional median filter. Either the sizes of a rectangular kernel or the footprint - of the kernel must be provided. The {size} parameter, if provided, + of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be equal along each axis. The - {footprint} if provided, must be an array that defines the shape of + *footprint* if provided, must be an array that defines the shape of the kernel by its non-zero elements. @@ -297,15 +299,15 @@ Derivative filters can be constructed in several ways. The function {gaussian_filter1d} described in section -:ref:`_ndimage_filter_functions_smoothing` can be used to calculate -derivatives along a given axis using the {order} parameter. Other +:ref:`ndimage-filter-functions-smoothing` can be used to calculate +derivatives along a given axis using the *order* parameter. Other derivative filters are the Prewitt and Sobel filters: - The {prewitt} function calculates a derivative along the given + The :func:`prewitt` function calculates a derivative along the given axis. - The {sobel} function calculates a derivative along the given + The :func:`sobel` function calculates a derivative along the given axis. @@ -316,21 +318,21 @@ calculate the second derivative along a given direction and to construct the Laplace filter: - The function {generic_laplace} calculates a laplace filter using - the function passed through {derivative2} to calculate second - derivatives. The function {derivative2} should have the following + The function :func:`generic_laplace` calculates a laplace filter using + the function passed through :func:`derivative2` to calculate second + derivatives. The function :func:`derivative2` should have the following signature: {derivative2(input, axis, output, mode, cval, \*extra_arguments, \*\*extra_keywords)} It should calculate the second derivative along the dimension - {axis}. If {output} is not {None} it should use that for the output - and return {None}, otherwise it should return the result. {mode}, - {cval} have the usual meaning. + *axis*. If *output* is not {None} it should use that for the output + and return {None}, otherwise it should return the result. *mode*, + *cval* have the usual meaning. - The {extra_arguments} and {extra_keywords} arguments can be used + The *extra_arguments* and *extra_keywords* arguments can be used to pass a tuple of extra arguments and a dictionary of named - arguments that are passed to {derivative2} at each call. + arguments that are passed to :func:`derivative2` at each call. For example: @@ -348,7 +350,7 @@ [ 0 0 1 0 0] [ 0 0 0 0 0]] - To demonstrate the use of the {extra_arguments} argument we could + To demonstrate the use of the *extra_arguments* argument we could do: :: @@ -378,44 +380,44 @@ The following two functions are implemented using -{generic_laplace} by providing appropriate functions for the +:func:`generic_laplace` by providing appropriate functions for the second derivative function: - The function {laplace} calculates the Laplace using discrete + The function :func:`laplace` calculates the Laplace using discrete differentiation for the second derivative (i.e. convolution with {[1, -2, 1]}). - The function {gaussian_laplace} calculates the Laplace using - {gaussian_filter} to calculate the second derivatives. The + The function :func:`gaussian_laplace` calculates the Laplace using + :func:`gaussian_filter` to calculate the second derivatives. The standard-deviations of the Gaussian filter along each axis are - passed through the parameter {sigma} as a sequence or numbers. If - {sigma} is not a sequence but a single number, the standard + passed through the parameter *sigma* as a sequence or numbers. If + *sigma* is not a sequence but a single number, the standard deviation of the filter is equal along all directions. The gradient magnitude is defined as the square root of the sum of the squares of the gradients in all directions. Similar to the -generic Laplace function there is a {generic_gradient_magnitude} +generic Laplace function there is a :func:`generic_gradient_magnitude` function that calculated the gradient magnitude of an array: - The function {generic_gradient_magnitude} calculates a gradient - magnitude using the function passed through {derivative} to - calculate first derivatives. The function {derivative} should have + The function :func:`generic_gradient_magnitude` calculates a gradient + magnitude using the function passed through :func:`derivative` to + calculate first derivatives. The function :func:`derivative` should have the following signature: {derivative(input, axis, output, mode, cval, \*extra_arguments, \*\*extra_keywords)} - It should calculate the derivative along the dimension {axis}. If - {output} is not {None} it should use that for the output and return - {None}, otherwise it should return the result. {mode}, {cval} have + It should calculate the derivative along the dimension *axis*. If + *output* is not {None} it should use that for the output and return + {None}, otherwise it should return the result. *mode*, *cval* have the usual meaning. - The {extra_arguments} and {extra_keywords} arguments can be used + The *extra_arguments* and *extra_keywords* arguments can be used to pass a tuple of extra arguments and a dictionary of named - arguments that are passed to {derivative} at each call. + arguments that are passed to *derivative* at each call. - For example, the {sobel} function fits the required signature: + For example, the :func:`sobel` function fits the required signature: :: @@ -428,28 +430,28 @@ [0 1 2 1 0] [0 0 0 0 0]] - See the documentation of {generic_laplace} for examples of using - the {extra_arguments} and {extra_keywords} arguments. + See the documentation of :func:`generic_laplace` for examples of using + the *extra_arguments* and *extra_keywords* arguments. -The {sobel} and {prewitt} functions fit the required signature and -can therefore directly be used with {generic_gradient_magnitude}. +The :func:`sobel` and :func:`prewitt` functions fit the required signature and +can therefore directly be used with :func:`generic_gradient_magnitude`. The following function implements the gradient magnitude using Gaussian derivatives: - The function {gaussian_gradient_magnitude} calculates the - gradient magnitude using {gaussian_filter} to calculate the first + The function :func:`gaussian_gradient_magnitude` calculates the + gradient magnitude using :func:`gaussian_filter` to calculate the first derivatives. The standard-deviations of the Gaussian filter along - each axis are passed through the parameter {sigma} as a sequence or - numbers. If {sigma} is not a sequence but a single number, the + each axis are passed through the parameter *sigma* as a sequence or + numbers. If *sigma* is not a sequence but a single number, the standard deviation of the filter is equal along all directions. +.. _ndimage-genericfilters: + Generic filter functions ------------------------ -.. _ndimage_genericfilters: - To implement filter functions, generic functions can be used that accept a callable object that implements the filtering operation. The iteration over the input and output arrays is handled by these generic functions, along with such @@ -457,17 +459,17 @@ callable object implementing a callback function that does the actual filtering work must be provided. The callback function can also be written in C and passed using a CObject (see -:ref:`_ndimage_ccallbacks` for more information). +:ref:`ndimage-ccallbacks` for more information). - The {generic_filter1d} function implements a generic + The :func:`generic_filter1d` function implements a generic one-dimensional filter function, where the actual filtering operation must be supplied as a python function (or other callable - object). The {generic_filter1d} function iterates over the lines - of an array and calls {function} at each line. The arguments that - are passed to {function} are one-dimensional arrays of the + object). The :func:`generic_filter1d` function iterates over the lines + of an array and calls :func:`function` at each line. The arguments that + are passed to :func:`function` are one-dimensional arrays of the {tFloat64} type. The first contains the values of the current line. It is extended at the beginning end the end, according to the - {filter_size} and {origin} arguments. The second array should be + *filter_size* and *origin* arguments. The second array should be modified in-place to provide the output values of the line. For example consider a correlation along one dimension: @@ -479,7 +481,7 @@ [27 32 38 41] [51 56 62 65]] - The same operation can be implemented using {generic_filter1d} as + The same operation can be implemented using :func:`generic_filter1d` as follows: :: @@ -498,7 +500,7 @@ function was called. Optionally extra arguments can be defined and passed to the filter - function. The {extra_arguments} and {extra_keywords} arguments + function. The *extra_arguments* and *extra_keywords* arguments can be used to pass a tuple of extra arguments and/or a dictionary of named arguments that are passed to derivative at each call. For example, we can pass the parameters of our filter as an argument: @@ -523,11 +525,11 @@ [51 56 62 65]] - The {generic_filter} function implements a generic filter + The :func:`generic_filter` function implements a generic filter function, where the actual filtering operation must be supplied as - a python function (or other callable object). The {generic_filter} - function iterates over the array and calls {function} at each - element. The argument of {function} is a one-dimensional array of + a python function (or other callable object). The :func:`generic_filter` + function iterates over the array and calls :func:`function` at each + element. The argument of :func:`function` is a one-dimensional array of the {tFloat64} type, that contains the values around the current element that are within the footprint of the filter. The function should return a single value that can be converted to a double @@ -541,7 +543,7 @@ [12 15 19 23] [28 31 35 39]] - The same operation can be implemented using {generic_filter} as + The same operation can be implemented using *generic_filter* as follows: :: @@ -559,15 +561,15 @@ equal to two, which was multiplied with the proper weights and the result summed. - When calling {generic_filter}, either the sizes of a rectangular - kernel or the footprint of the kernel must be provided. The {size} + When calling :func:`generic_filter`, either the sizes of a rectangular + kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be equal - along each axis. The {footprint}, if provided, must be an array + along each axis. The *footprint*, if provided, must be an array that defines the shape of the kernel by its non-zero elements. Optionally extra arguments can be defined and passed to the filter - function. The {extra_arguments} and {extra_keywords} arguments + function. The *extra_arguments* and *extra_keywords* arguments can be used to pass a tuple of extra arguments and/or a dictionary of named arguments that are passed to derivative at each call. For example, we can pass the parameters of our filter as an argument: @@ -599,7 +601,7 @@ the filter dependening on spatial location. Here is an example of using a class that implements the filter and keeps track of the current coordinates while iterating. It performs the same filter -operation as described above for {generic_filter}, but +operation as described above for :func:`generic_filter`, but additionally prints the current coordinates: :: @@ -645,9 +647,9 @@ [12 15 19 23] [28 31 35 39]] -For the {generic_filter1d} function the same approach works, +For the :func:`generic_filter1d` function the same approach works, except that this function does not iterate over the axis that is -being filtered. The example for {generic_filte1d} then becomes +being filtered. The example for :func:`generic_filter1d` then becomes this: :: @@ -688,53 +690,53 @@ [51 56 62 65]] Fourier domain filters -====================== +---------------------- The functions described in this section perform filtering operations in the Fourier domain. Thus, the input array of such a function should be compatible with an inverse Fourier transform -function, such as the functions from the {numarray.fft} module. We +function, such as the functions from the {scipy.fft} module. We therefore have to deal with arrays that may be the result of a real or a complex Fourier transform. In the case of a real Fourier transform only half of the of the symmetric complex transform is stored. Additionally, it needs to be known what the length of the axis was that was transformed by the real fft. The functions -described here provide a parameter {n} that in the case of a real +described here provide a parameter *n* that in the case of a real transform must be equal to the length of the real transform axis before transformation. If this parameter is less than zero, it is assumed that the input array was the result of a complex Fourier -transform. The parameter {axis} can be used to indicate along which +transform. The parameter *axis* can be used to indicate along which axis the real transform was executed. - The {fourier_shift} function multiplies the input array with the + The :func:`fourier_shift` function multiplies the input array with the multi-dimensional Fourier transform of a shift operation for the - given shift. The {shift} parameter is a sequences of shifts for + given shift. The *shift* parameter is a sequences of shifts for each dimension, or a single value for all dimensions. - The {fourier_gaussian} function multiplies the input array with + The :func:`fourier_gaussian` function multiplies the input array with the multi-dimensional Fourier transform of a Gaussian filter with - given standard-deviations {sigma}. The {sigma} parameter is a + given standard-deviations *sigma*. The *sigma* parameter is a sequences of values for each dimension, or a single value for all dimensions. - The {fourier_uniform} function multiplies the input array with the + The :func:`fourier_uniform` function multiplies the input array with the multi-dimensional Fourier transform of a uniform filter with given - sizes {size}. The {size} parameter is a sequences of values for + sizes *size*. The *size* parameter is a sequences of values for each dimension, or a single value for all dimensions. - The {fourier_ellipsoid} function multiplies the input array with + The :func:`fourier_ellipsoid` function multiplies the input array with the multi-dimensional Fourier transform of a elliptically shaped - filter with given sizes {size}. The {size} parameter is a sequences + filter with given sizes *size*. The *size* parameter is a sequences of values for each dimension, or a single value for all dimensions. {This function is only implemented for dimensions 1, 2, and 3.} Interpolation functions -======================= +----------------------- This section describes various interpolation functions that are based on B-spline theory. A good introduction to B-splines can be @@ -743,22 +745,22 @@ 22-38, November 1999. {Spline pre-filters} Interpolation using splines of an order larger than 1 requires a pre- filtering step. The interpolation functions described in section -:ref:`_ndimage_interpolation` apply pre-filtering by calling -{spline_filter}, but they can be instructed not to do this by -setting the {prefilter} keyword equal to {False}. This is useful if +:ref:`ndimage-interpolation` apply pre-filtering by calling +:func:`spline_filter`, but they can be instructed not to do this by +setting the *prefilter* keyword equal to {False}. This is useful if more than one interpolation operation is done on the same array. In this case it is more efficient to do the pre-filtering only once and use a prefiltered array as the input of the interpolation functions. The following two functions implement the pre-filtering: - The {spline_filter1d} function calculates a one-dimensional spline + The :func:`spline_filter1d` function calculates a one-dimensional spline filter along the given axis. An output array can optionally be provided. The order of the spline must be larger then 1 and less than 6. - The {spline_filter} function calculates a multi-dimensional spline + The :func:`spline_filter` function calculates a multi-dimensional spline filter. {The multi-dimensional filter is implemented as a sequence of @@ -769,25 +771,25 @@ This can be prevented by specifying a output type of high precision.} +.. _ndimage-interpolation: + Interpolation functions ----------------------- -.. _ndimage_interpolation: - Following functions all employ spline interpolation to effect some type of geometric transformation of the input array. This requires a mapping of the output coordinates to the input coordinates, and therefore the possibility arises that input values outside the boundaries are needed. This problem is -solved in the same way as described in section :ref:`_ndimage_filter_functions` +solved in the same way as described in section :ref:`ndimage-filter-functions` for the multi-dimensional filter functions. Therefore these functions all -support a {mode} parameter that determines how the boundaries are handled, and -a {cval} parameter that gives a constant value in case that the {'constant'} +support a *mode* parameter that determines how the boundaries are handled, and +a *cval* parameter that gives a constant value in case that the {'constant'} mode is used. - The {geometric_transform} function applies an arbitrary geometric - transform to the input. The given {mapping} function is called at + The :func:`geometric_transform` function applies an arbitrary geometric + transform to the input. The given *mapping* function is called at each point in the output to find the corresponding coordinates in - the input. {mapping} must be a callable object that accepts a tuple + the input. *mapping* must be a callable object that accepts a tuple of length equal to the output array rank and returns the corresponding input coordinates as a tuple of length equal to the input array rank. The output shape and output type can optionally @@ -809,7 +811,7 @@ [ 0. 8.2625 9.6375]] Optionally extra arguments can be defined and passed to the filter - function. The {extra_arguments} and {extra_keywords} arguments + function. The *extra_arguments* and *extra_keywords* arguments can be used to pass a tuple of extra arguments and/or a dictionary of named arguments that are passed to derivative at each call. For example, we can pass the shifts in our example as arguments: @@ -835,17 +837,17 @@ [ 0. 4.8125 6.1875] [ 0. 8.2625 9.6375]] - {The mapping function can also be written in C and passed using a CObject. See :ref:`_ndimage_ccallbacks` for more information.} + {The mapping function can also be written in C and passed using a CObject. See :ref:`ndimage-ccallbacks` for more information.} - The function {map_coordinates} applies an arbitrary coordinate + The function :func:`map_coordinates` applies an arbitrary coordinate transformation using the given array of coordinates. The shape of the output is derived from that of the coordinate array by dropping - the first axis. The parameter {coordinates} is used to find for + the first axis. The parameter *coordinates* is used to find for each point in the output the corresponding coordinates in the - input. The values of {coordinates} along the first axis are the + input. The values of *coordinates* along the first axis are the coordinates in the input array at which the output value is found. - (See also the numarray {coordinates} function.) Since the + (See also the numarray *coordinates* function.) Since the coordinates may be non- integer coordinates, the value of the input at these coordinates is determined by spline interpolation of the requested order. Here is an example that interpolates a 2D array at @@ -863,12 +865,12 @@ [ 1.3625 7. ] - The {affine_transform} function applies an affine transformation - to the input array. The given transformation {matrix} and {offset} + The :func:`affine_transform` function applies an affine transformation + to the input array. The given transformation *matrix* and *offset* are used to find for each point in the output the corresponding coordinates in the input. The value of the input at the calculated coordinates is determined by spline interpolation of the requested - order. The transformation {matrix} must be two-dimensional or can + order. The transformation *matrix* must be two-dimensional or can also be given as a one-dimensional sequence or array. In the latter case, it is assumed that the matrix is diagonal. A more efficient interpolation algorithm is then applied that exploits the @@ -877,33 +879,33 @@ shape and type. - The {shift} function returns a shifted version of the input, using - spline interpolation of the requested {order}. + The :func:`shift` function returns a shifted version of the input, using + spline interpolation of the requested *order*. - The {zoom} function returns a rescaled version of the input, using - spline interpolation of the requested {order}. + The :func:`zoom` function returns a rescaled version of the input, using + spline interpolation of the requested *order*. - The {rotate} function returns the input array rotated in the plane - defined by the two axes given by the parameter {axes}, using spline - interpolation of the requested {order}. The angle must be given in - degrees. If {reshape} is true, then the size of the output array is + The :func:`rotate` function returns the input array rotated in the plane + defined by the two axes given by the parameter *axes*, using spline + interpolation of the requested *order*. The angle must be given in + degrees. If *reshape* is true, then the size of the output array is adapted to contain the rotated input. +.. _ndimage-binary-morphology: + Binary morphology -================= +----------------- -.. _ndimage_binary_morphology: - - The {generate_binary_structure} functions generates a binary + The :func:`generate_binary_structure` functions generates a binary structuring element for use in binary morphology operations. The - {rank} of the structure must be provided. The size of the structure + *rank* of the structure must be provided. The size of the structure that is returned is equal to three in each direction. The value of each element is equal to one if the square of the Euclidean distance from the element to the center is less or equal to - {connectivity}. For instance, two dimensional 4-connected and + *connectivity*. For instance, two dimensional 4-connected and 8-connected structures are generated as follows: :: @@ -921,34 +923,34 @@ Most binary morphology functions can be expressed in terms of the basic operations erosion and dilation: - The {binary_erosion} function implements binary erosion of arrays + The :func:`binary_erosion` function implements binary erosion of arrays of arbitrary rank with the given structuring element. The origin parameter controls the placement of the structuring element as - described in section :ref:`_ndimage_filter_functions`. If no + described in section :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal - to one is generated using {generate_binary_structure}. The - {border_value} parameter gives the value of the array outside - boundaries. The erosion is repeated {iterations} times. If - {iterations} is less than one, the erosion is repeated until the - result does not change anymore. If a {mask} array is given, only + to one is generated using :func:`generate_binary_structure`. The + *border_value* parameter gives the value of the array outside + boundaries. The erosion is repeated *iterations* times. If + *iterations* is less than one, the erosion is repeated until the + result does not change anymore. If a *mask* array is given, only those elements with a true value at the corresponding mask element are modified at each iteration. - The {binary_dilation} function implements binary dilation of + The :func:`binary_dilation` function implements binary dilation of arrays of arbitrary rank with the given structuring element. The origin parameter controls the placement of the structuring element - as described in section :ref:`_ndimage_filter_functions`. If no + as described in section :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal - to one is generated using {generate_binary_structure}. The - {border_value} parameter gives the value of the array outside - boundaries. The dilation is repeated {iterations} times. If - {iterations} is less than one, the dilation is repeated until the - result does not change anymore. If a {mask} array is given, only + to one is generated using :func:`generate_binary_structure`. The + *border_value* parameter gives the value of the array outside + boundaries. The dilation is repeated *iterations* times. If + *iterations* is less than one, the dilation is repeated until the + result does not change anymore. If a *mask* array is given, only those elements with a true value at the corresponding mask element are modified at each iteration. - Here is an example of using {binary_dilation} to find all elements + Here is an example of using :func:`binary_dilation` to find all elements that touch the border, by repeatedly dilating an empty array from the border using the data array as the mask: @@ -968,16 +970,16 @@ [0 0 0 0 0]] -The {binary_erosion} and {binary_dilation} functions both have an -{iterations} parameter which allows the erosion or dilation to be +The :func:`binary_erosion` and :func:`binary_dilation` functions both have an +*iterations* parameter which allows the erosion or dilation to be repeated a number of times. Repeating an erosion or a dilation with -a given structure {n} times is equivalent to an erosion or a +a given structure *n* times is equivalent to an erosion or a dilation with a structure that is {n-1} times dilated with itself. A function is provided that allows the calculation of a structure that is dilated a number of times with itself: - The {iterate_structure} function returns a structure by dilation - of the input structure {iteration} - 1 times with itself. For + The :func:`iterate_structure` function returns a structure by dilation + of the input structure *iteration* - 1 times with itself. For instance: :: @@ -996,11 +998,11 @@ If the origin of the original structure is equal to 0, then it is also equal to 0 for the iterated structure. If not, the origin must - also be adapted if the equivalent of the {iterations} erosions or + also be adapted if the equivalent of the *iterations* erosions or dilations must be achieved with the iterated structure. The adapted origin is simply obtained by multiplying with the number of - iterations. For convenience the {iterate_structure} also returns - the adapted origin if the {origin} parameter is not {None}: + iterations. For convenience the :func:`iterate_structure` also returns + the adapted origin if the *origin* parameter is not {None}: :: @@ -1016,151 +1018,149 @@ d dilation. Following functions provide a few of these operations for convenience: - The {binary_opening} function implements binary opening of arrays + The :func:`binary_opening` function implements binary opening of arrays of arbitrary rank with the given structuring element. Binary opening is equivalent to a binary erosion followed by a binary dilation with the same structuring element. The origin parameter controls the placement of the structuring element as described in - section :ref:`_ndimage_filter_functions`. If no structuring element is + section :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal to one is generated - using {generate_binary_structure}. The {iterations} parameter + using :func:`generate_binary_structure`. The *iterations* parameter gives the number of erosions that is performed followed by the same number of dilations. - The {binary_closing} function implements binary closing of arrays + The :func:`binary_closing` function implements binary closing of arrays of arbitrary rank with the given structuring element. Binary closing is equivalent to a binary dilation followed by a binary erosion with the same structuring element. The origin parameter controls the placement of the structuring element as described in - section :ref:`_ndimage_filter_functions`. If no structuring element is + section :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal to one is generated - using {generate_binary_structure}. The {iterations} parameter + using :func:`generate_binary_structure`. The *iterations* parameter gives the number of dilations that is performed followed by the same number of erosions. - The {binary_fill_holes} function is used to close holes in + The :func:`binary_fill_holes` function is used to close holes in objects in a binary image, where the structure defines the connectivity of the holes. The origin parameter controls the placement of the structuring element as described in section - :ref:`_ndimage_filter_functions`. If no structuring element is + :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal to one is generated - using {generate_binary_structure}. + using :func:`generate_binary_structure`. - The {binary_hit_or_miss} function implements a binary + The :func:`binary_hit_or_miss` function implements a binary hit-or-miss transform of arrays of arbitrary rank with the given structuring elements. The hit-or-miss transform is calculated by erosion of the input with the first structure, erosion of the logical *not* of the input with the second structure, followed by the logical *and* of these two erosions. The origin parameters control the placement of the structuring elements as described in - section :ref:`_ndimage_filter_functions`. If {origin2} equals {None} it + section :ref:`ndimage-filter-functions`. If {origin2} equals {None} it is set equal to the {origin1} parameter. If the first structuring element is not provided, a structuring element with connectivity - equal to one is generated using {generate_binary_structure}, if + equal to one is generated using :func:`generate_binary_structure`, if {structure2} is not provided, it is set equal to the logical *not* of {structure1}. +.. _ndimage-grey-morphology: + Grey-scale morphology -===================== +--------------------- -.. _ndimage_grey_morphology: - - - Grey-scale morphology operations are the equivalents of binary morphology operations that operate on arrays with arbitrary values. Below we describe the grey-scale equivalents of erosion, dilation, opening and closing. These operations are implemented in a similar fashion as the filters described in section -:ref:`_ndimage_filter_functions`, and we refer to this section for the +:ref:`ndimage-filter-functions`, and we refer to this section for the description of filter kernels and footprints, and the handling of array borders. The grey-scale morphology operations optionally take -a {structure} parameter that gives the values of the structuring +a *structure* parameter that gives the values of the structuring element. If this parameter is not given the structuring element is assumed to be flat with a value equal to zero. The shape of the -structure can optionally be defined by the {footprint} parameter. +structure can optionally be defined by the *footprint* parameter. If this parameter is not given, the structure is assumed to be -rectangular, with sizes equal to the dimensions of the {structure} -array, or by the {size} parameter if {structure} is not given. The -{size} parameter is only used if both {structure} and {footprint} +rectangular, with sizes equal to the dimensions of the *structure* +array, or by the *size* parameter if *structure* is not given. The +*size* parameter is only used if both *structure* and *footprint* are not given, in which case the structuring element is assumed to -be rectangular and flat with the dimensions given by {size}. The -{size} parameter, if provided, must be a sequence of sizes or a +be rectangular and flat with the dimensions given by *size*. The +*size* parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be -equal along each axis. The {footprint} parameter, if provided, must +equal along each axis. The *footprint* parameter, if provided, must be an array that defines the shape of the kernel by its non-zero elements. Similar to binary erosion and dilation there are operations for grey-scale erosion and dilation: - The {grey_erosion} function calculates a multi-dimensional grey- + The :func:`grey_erosion` function calculates a multi-dimensional grey- scale erosion. - The {grey_dilation} function calculates a multi-dimensional grey- + The :func:`grey_dilation` function calculates a multi-dimensional grey- scale dilation. Grey-scale opening and closing operations can be defined similar to their binary counterparts: - The {grey_opening} function implements grey-scale opening of + The :func:`grey_opening` function implements grey-scale opening of arrays of arbitrary rank. Grey-scale opening is equivalent to a grey-scale erosion followed by a grey-scale dilation. - The {grey_closing} function implements grey-scale closing of + The :func:`grey_closing` function implements grey-scale closing of arrays of arbitrary rank. Grey-scale opening is equivalent to a grey-scale dilation followed by a grey-scale erosion. - The {morphological_gradient} function implements a grey-scale + The :func:`morphological_gradient` function implements a grey-scale morphological gradient of arrays of arbitrary rank. The grey-scale morphological gradient is equal to the difference of a grey-scale dilation and a grey-scale erosion. - The {morphological_laplace} function implements a grey-scale + The :func:`morphological_laplace` function implements a grey-scale morphological laplace of arrays of arbitrary rank. The grey-scale morphological laplace is equal to the sum of a grey-scale dilation and a grey-scale erosion minus twice the input. - The {white_tophat} function implements a white top-hat filter of + The :func:`white_tophat` function implements a white top-hat filter of arrays of arbitrary rank. The white top-hat is equal to the difference of the input and a grey-scale opening. - The {black_tophat} function implements a black top-hat filter of + The :func:`black_tophat` function implements a black top-hat filter of arrays of arbitrary rank. The black top-hat is equal to the difference of the a grey-scale closing and the input. +.. _ndimage-distance-transforms: + Distance transforms -=================== +------------------- -.. _ndimage_distance_transforms: - Distance transforms are used to calculate the minimum distance from each element of an object to the background. The following functions implement distance transforms for three different distance metrics: Euclidean, City Block, and Chessboard distances. - The function {distance_transform_cdt} uses a chamfer type + The function :func:`distance_transform_cdt` uses a chamfer type algorithm to calculate the distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest distance to the background (all non-object elements). The structure determines the type of chamfering that is done. If the structure is equal to 'cityblock' a structure is - generated using {generate_binary_structure} with a squared + generated using :func:`generate_binary_structure` with a squared distance equal to 1. If the structure is equal to 'chessboard', a - structure is generated using {generate_binary_structure} with a + structure is generated using :func:`generate_binary_structure` with a squared distance equal to the rank of the array. These choices correspond to the common interpretations of the cityblock and the chessboard distancemetrics in two dimensions. @@ -1168,11 +1168,11 @@ In addition to the distance transform, the feature transform can be calculated. In this case the index of the closest background element is returned along the first axis of the result. The - {return_distances}, and {return_indices} flags can be used to + *return_distances*, and *return_indices* flags can be used to indicate if the distance transform, the feature transform, or both must be returned. - The {distances} and {indices} arguments can be used to give + The *distances* and *indices* arguments can be used to give optional output arrays that must be of the correct size and type (both {Int32}). @@ -1182,7 +1182,7 @@ 27:321-345, 1984. - The function {distance_transform_edt} calculates the exact + The function :func:`distance_transform_edt` calculates the exact euclidean distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest euclidean distance to the background (all non-object elements). @@ -1190,16 +1190,16 @@ In addition to the distance transform, the feature transform can be calculated. In this case the index of the closest background element is returned along the first axis of the result. The - {return_distances}, and {return_indices} flags can be used to + *return_distances*, and *return_indices* flags can be used to indicate if the distance transform, the feature transform, or both must be returned. Optionally the sampling along each axis can be given by the - {sampling} parameter which should be a sequence of length equal to + *sampling* parameter which should be a sequence of length equal to the input rank, or a single number in which the sampling is assumed to be equal along all axes. - The {distances} and {indices} arguments can be used to give + The *distances* and *indices* arguments can be used to give optional output arrays that must be of the correct size and type ({Float64} and {Int32}). @@ -1209,7 +1209,7 @@ in arbitrary dimensions. IEEE Trans. PAMI 25, 265-270, 2003. - The function {distance_transform_bf} uses a brute-force algorithm + The function :func:`distance_transform_bf` uses a brute-force algorithm to calculate the distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest distance to the background (all non-object elements). The @@ -1219,17 +1219,17 @@ In addition to the distance transform, the feature transform can be calculated. In this case the index of the closest background element is returned along the first axis of the result. The - {return_distances}, and {return_indices} flags can be used to + *return_distances*, and *return_indices* flags can be used to indicate if the distance transform, the feature transform, or both must be returned. Optionally the sampling along each axis can be given by the - {sampling} parameter which should be a sequence of length equal to + *sampling* parameter which should be a sequence of length equal to the input rank, or a single number in which the sampling is assumed to be equal along all axes. This parameter is only used in the case of the euclidean distance transform. - The {distances} and {indices} arguments can be used to give + The *distances* and *indices* arguments can be used to give optional output arrays that must be of the correct size and type ({Float64} and {Int32}). @@ -1241,11 +1241,11 @@ Segmentation and labeling -========================= +------------------------- Segmentation is the process of separating objects of interest from the background. The most simple approach is probably intensity -thresholding, which is easily done with {numarray} functions: +thresholding, which is easily done with :mod:`numpy` functions: :: @@ -1260,13 +1260,13 @@ [0 0 0 0 1 0]] The result is a binary image, in which the individual objects still -need to be identified and labeled. The function {label} generates +need to be identified and labeled. The function :func:`label` generates an array where each object is assigned a unique number: - The {label} function generates an array where the objects in the + The :func:`label` function generates an array where the objects in the input are labeled with an integer index. It returns a tuple consisting of the array of object labels and the number of objects - found, unless the {output} parameter is given, in which case only + found, unless the *output* parameter is given, in which case only the number of objects is returned. The connectivity of the objects is defined by a structuring element. For instance, in two dimensions using a four-connected structuring element gives: @@ -1297,7 +1297,7 @@ [0 0 0 0 1 0]] If no structuring element is provided, one is generated by calling - {generate_binary_structure} (see section :ref:`_ndimage_morphology`) + *generate_binary_structure* (see section :ref:`ndimage-binary-morphology`) using a connectivity of one (which in 2D is the 4-connected structure of the first example). The input can be of any type, any value not equal to zero is taken to be part of an object. This is @@ -1323,13 +1323,13 @@ There is a large number of other approaches for segmentation, for instance from an estimation of the borders of the objects that can be obtained for instance by derivative filters. One such an -approach is watershed segmentation. The function {watershed_ift} +approach is watershed segmentation. The function :func:`watershed_ift` generates an array where each object is assigned a unique label, from an array that localizes the object borders, generated for instance by a gradient magnitude filter. It uses an array containing initial markers for the objects: - The {watershed_ift} function applies a watershed from markers + The :func:`watershed_ift` function applies a watershed from markers algorithm, using an Iterative Forest Transform, as described in: P. Felkel, R. Wegenkittl, and M. Bruckschwaiger, "Implementation and Complexity of the Watershed-from-Markers Algorithm Computed as a @@ -1390,7 +1390,7 @@ The result is that the object (marker=2) is smaller because the second marker was processed earlier. This may not be the desired effect if the first marker was supposed to designate a background - object. Therefore {watershed_ift} treats markers with a negative + object. Therefore :func:`watershed_ift` treats markers with a negative value explicitly as background markers and processes them after the normal markers. For instance, replacing the first marker by a negative marker gives a result similar to the first example: @@ -1415,10 +1415,10 @@ The connectivity of the objects is defined by a structuring element. If no structuring element is provided, one is generated by - calling {generate_binary_structure} (see section - :ref:`_ndimage_morphology`) using a connectivity of one (which in 2D is - a 4-connected structure.) For example, using an 8-connected - structure with the last example yields a different object: + calling :func:`generate_binary_structure` (see section + :ref:`ndimage-binary-morphology`) using a connectivity of one + (which in 2D is a 4-connected structure.) For example, using + an 8-connected structure with the last example yields a different object: :: @@ -1437,14 +1437,14 @@ Object measurements -=================== +------------------- Given an array of labeled objects, the properties of the individual -objects can be measured. The {find_objects} function can be used +objects can be measured. The :func:`find_objects` function can be used to generate a list of slices that for each object, give the smallest sub-array that fully contains the object: - The {find_objects} finds all objects in a labeled array and + The :func:`find_objects` function finds all objects in a labeled array and returns a list of slices that correspond to the smallest regions in the array that contains the object. For instance: @@ -1461,10 +1461,10 @@ [1 1 1] [0 1 0]] - {find_objects} returns slices for all objects, unless the - {max_label} parameter is larger then zero, in which case only the - first {max_label} objects are returned. If an index is missing in - the {label} array, {None} is return instead of a slice. For + :func:`find_objects` returns slices for all objects, unless the + *max_label* parameter is larger then zero, in which case only the + first *max_label* objects are returned. If an index is missing in + the *label* array, {None} is return instead of a slice. For example: :: @@ -1473,7 +1473,7 @@ [(slice(0, 1, None),), None, (slice(2, 3, None),)] -The list of slices generated by {find_objects} is useful to find +The list of slices generated by :func:`find_objects` is useful to find the position and dimensions of the objects in the array, but can also be used to perform measurements on the individual objects. Say we want to find the sum of the intensities of an object in image: @@ -1522,118 +1522,118 @@ >>> print sum(image, labels, [0, 2]) [178.0, 80.0] -The measurement functions described below all support the {index} +The measurement functions described below all support the *index* parameter to indicate which object(s) should be measured. The -default value of {index} is {None}. This indicates that all +default value of *index* is {None}. This indicates that all elements where the label is larger than zero should be treated as a -single object and measured. Thus, in this case the {labels} array +single object and measured. Thus, in this case the *labels* array is treated as a mask defined by the elements that are larger than -zero. If {index} is a number or a sequence of numbers it gives the -labels of the objects that are measured. If {index} is a sequence, +zero. If *index* is a number or a sequence of numbers it gives the +labels of the objects that are measured. If *index* is a sequence, a list of the results is returned. Functions that return more than -one result, return their result as a tuple if {index} is a single -number, or as a tuple of lists, if {index} is a sequence. +one result, return their result as a tuple if *index* is a single +number, or as a tuple of lists, if *index* is a sequence. - The {sum} function calculates the sum of the elements of the object - with label(s) given by {index}, using the {labels} array for the - object labels. If {index} is {None}, all elements with a non-zero - label value are treated as a single object. If {label} is {None}, - all elements of {input} are used in the calculation. + The :func:`sum` function calculates the sum of the elements of the object + with label(s) given by *index*, using the *labels* array for the + object labels. If *index* is {None}, all elements with a non-zero + label value are treated as a single object. If *label* is {None}, + all elements of *input* are used in the calculation. - The {mean} function calculates the mean of the elements of the - object with label(s) given by {index}, using the {labels} array for - the object labels. If {index} is {None}, all elements with a - non-zero label value are treated as a single object. If {label} is - {None}, all elements of {input} are used in the calculation. + The :func:`mean` function calculates the mean of the elements of the + object with label(s) given by *index*, using the *labels* array for + the object labels. If *index* is {None}, all elements with a + non-zero label value are treated as a single object. If *label* is + {None}, all elements of *input* are used in the calculation. - The {variance} function calculates the variance of the elements of - the object with label(s) given by {index}, using the {labels} array - for the object labels. If {index} is {None}, all elements with a - non-zero label value are treated as a single object. If {label} is - {None}, all elements of {input} are used in the calculation. + The :func:`variance` function calculates the variance of the elements of + the object with label(s) given by *index*, using the *labels* array + for the object labels. If *index* is {None}, all elements with a + non-zero label value are treated as a single object. If *label* is + {None}, all elements of *input* are used in the calculation. - The {standard_deviation} function calculates the standard + The :func:`standard_deviation` function calculates the standard deviation of the elements of the object with label(s) given by - {index}, using the {labels} array for the object labels. If {index} + *index*, using the *labels* array for the object labels. If *index* is {None}, all elements with a non-zero label value are treated as - a single object. If {label} is {None}, all elements of {input} are + a single object. If *label* is {None}, all elements of *input* are used in the calculation. - The {minimum} function calculates the minimum of the elements of - the object with label(s) given by {index}, using the {labels} array - for the object labels. If {index} is {None}, all elements with a - non-zero label value are treated as a single object. If {label} is - {None}, all elements of {input} are used in the calculation. + The :func:`minimum` function calculates the minimum of the elements of + the object with label(s) given by *index*, using the *labels* array + for the object labels. If *index* is {None}, all elements with a + non-zero label value are treated as a single object. If *label* is + {None}, all elements of *input* are used in the calculation. - The {maximum} function calculates the maximum of the elements of - the object with label(s) given by {index}, using the {labels} array - for the object labels. If {index} is {None}, all elements with a - non-zero label value are treated as a single object. If {label} is - {None}, all elements of {input} are used in the calculation. + The :func:`maximum` function calculates the maximum of the elements of + the object with label(s) given by *index*, using the *labels* array + for the object labels. If *index* is {None}, all elements with a + non-zero label value are treated as a single object. If *label* is + {None}, all elements of *input* are used in the calculation. - The {minimum_position} function calculates the position of the + The :func:`minimum_position` function calculates the position of the minimum of the elements of the object with label(s) given by - {index}, using the {labels} array for the object labels. If {index} + *index*, using the *labels* array for the object labels. If *index* is {None}, all elements with a non-zero label value are treated as - a single object. If {label} is {None}, all elements of {input} are + a single object. If *label* is {None}, all elements of *input* are used in the calculation. - The {maximum_position} function calculates the position of the + The :func:`maximum_position` function calculates the position of the maximum of the elements of the object with label(s) given by - {index}, using the {labels} array for the object labels. If {index} + *index*, using the *labels* array for the object labels. If *index* is {None}, all elements with a non-zero label value are treated as - a single object. If {label} is {None}, all elements of {input} are + a single object. If *label* is {None}, all elements of *input* are used in the calculation. - The {extrema} function calculates the minimum, the maximum, and + The :func:`extrema` function calculates the minimum, the maximum, and their positions, of the elements of the object with label(s) given - by {index}, using the {labels} array for the object labels. If - {index} is {None}, all elements with a non-zero label value are - treated as a single object. If {label} is {None}, all elements of - {input} are used in the calculation. The result is a tuple giving + by *index*, using the *labels* array for the object labels. If + *index* is {None}, all elements with a non-zero label value are + treated as a single object. If *label* is {None}, all elements of + *input* are used in the calculation. The result is a tuple giving the minimum, the maximum, the position of the mininum and the postition of the maximum. The result is the same as a tuple formed - by the results of the functions {minimum}, {maximum}, - {minimum_position}, and {maximum_position} that are described + by the results of the functions *minimum*, *maximum*, + *minimum_position*, and *maximum_position* that are described above. - The {center_of_mass} function calculates the center of mass of - the of the object with label(s) given by {index}, using the - {labels} array for the object labels. If {index} is {None}, all + The :func:`center_of_mass` function calculates the center of mass of + the of the object with label(s) given by *index*, using the + *labels* array for the object labels. If *index* is {None}, all elements with a non-zero label value are treated as a single - object. If {label} is {None}, all elements of {input} are used in + object. If *label* is {None}, all elements of *input* are used in the calculation. - The {histogram} function calculates a histogram of the of the - object with label(s) given by {index}, using the {labels} array for - the object labels. If {index} is {None}, all elements with a - non-zero label value are treated as a single object. If {label} is - {None}, all elements of {input} are used in the calculation. - Histograms are defined by their minimum ({min}), maximum ({max}) - and the number of bins ({bins}). They are returned as + The :func:`histogram` function calculates a histogram of the of the + object with label(s) given by *index*, using the *labels* array for + the object labels. If *index* is {None}, all elements with a + non-zero label value are treated as a single object. If *label* is + {None}, all elements of *input* are used in the calculation. + Histograms are defined by their minimum (*min*), maximum (*max*) + and the number of bins (*bins*). They are returned as one-dimensional arrays of type Int32. -Extending {nd_image} in C -============================ +.. _ndimage-ccallbacks: -.. _ndimage_ccallbacks: +Extending *ndimage* in C +------------------------- -{C callback functions} A few functions in the {numarray.nd_image} take a call-back argument. This can be a python function, but also a CObject containing a pointer to a C function. To use this feature, you must write your own C extension that defines the function, and define a python function that +{C callback functions} A few functions in the {numarray.ndimage} take a call-back argument. This can be a python function, but also a CObject containing a pointer to a C function. To use this feature, you must write your own C extension that defines the function, and define a python function that returns a CObject containing a pointer to this function. An example of a function that supports this is -{geometric_transform} (see section :ref:`_ndimage_interpolation`). +:func:`geometric_transform` (see section :ref:`ndimage-interpolation`). You can pass it a python callable object that defines a mapping from all output coordinates to corresponding coordinates in the input array. This mapping function can also be a C function, which @@ -1660,17 +1660,17 @@ } This function is called at every element of the output array, -passing the current coordinates in the {output_coordinates} array. -On return, the {input_coordinates} array must contain the +passing the current coordinates in the *output_coordinates* array. +On return, the *input_coordinates* array must contain the coordinates at which the input is interpolated. The ranks of the -input and output array are passed through {output_rank} and -{input_rank}. The value of the shift is passed through the -{callback_data} argument, which is a pointer to void. The function +input and output array are passed through *output_rank* and +*input_rank*. The value of the shift is passed through the +*callback_data* argument, which is a pointer to void. The function returns an error status, in this case always 1, since no error can occur. A pointer to this function and a pointer to the shift value must be -passed to {geometric_transform}. Both are passed by a single +passed to :func:`geometric_transform`. Both are passed by a single CObject which is created by the following python extension function: @@ -1737,23 +1737,23 @@ [ 0. 4.8125 6.1875] [ 0. 8.2625 9.6375]] -C Callback functions for use with {nd_image} functions must all +C Callback functions for use with :mod:`ndimage` functions must all be written according to this scheme. The next section lists the -{nd_image} functions that acccept a C callback function and +:mod:`ndimage` functions that acccept a C callback function and gives the prototype of the callback function. Functions that support C callback functions ------------------------------------------- -The {nd_image} functions that support C callback functions are +The :func:`ndimage` functions that support C callback functions are described here. Obviously, the prototype of the function that is provided to these functions must match exactly that what they expect. Therefore we give here the prototypes of the callback functions. All these callback functions accept a void -{callback_data} pointer that must be wrapped in a CObject using +*callback_data* pointer that must be wrapped in a CObject using the Python {PyCObject_FromVoidPtrAndDesc} function, which can also accept a pointer to a destructor function to free any memory -allocated for {callback_data}. If {callback_data} is not needed, +allocated for *callback_data*. If *callback_data* is not needed, {PyCObject_FromVoidPtr} may be used instead. The callback functions must return an integer error status that is equal to zero if something went wrong, or 1 otherwise. If an error occurs, you @@ -1761,45 +1761,45 @@ message before returning, otherwise, a default error message is set by the calling function. -The function {generic_filter} (see section -:ref:`_ndimage_genericfilters`) accepts a callback function with the +The function :func:`generic_filter` (see section +:ref:`ndimage-genericfilters`) accepts a callback function with the following prototype: The calling function iterates over the elements of the input and output arrays, calling the callback function at each element. The elements within the footprint of the filter at the current element - are passed through the {buffer} parameter, and the number of - elements within the footprint through {filter_size}. The - calculated valued should be returned in the {return_value} + are passed through the *buffer* parameter, and the number of + elements within the footprint through *filter_size*. The + calculated valued should be returned in the *return_value* argument. -The function {generic_filter1d} (see section -:ref:`_ndimage_genericfilters`) accepts a callback function with the +The function :func:`generic_filter1d` (see section +:ref:`ndimage-genericfilters`) accepts a callback function with the following prototype: The calling function iterates over the lines of the input and output arrays, calling the callback function at each line. The current line is extended according to the border conditions set by the calling function, and the result is copied into the array that - is passed through the {input_line} array. The length of the input - line (after extension) is passed through {input_length}. The + is passed through the *input_line* array. The length of the input + line (after extension) is passed through *input_length*. The callback function should apply the 1D filter and store the result - in the array passed through {output_line}. The length of the - output line is passed through {output_length}. + in the array passed through *output_line*. The length of the + output line is passed through *output_length*. -The function {geometric_transform} (see section -:ref:`_ndimage_interpolation`) expects a function with the following +The function :func:`geometric_transform` (see section +:ref:`ndimage-interpolation`) expects a function with the following prototype: The calling function iterates over the elements of the output array, calling the callback function at each element. The coordinates of the current output element are passed through - {output_coordinates}. The callback function must return the + *output_coordinates*. The callback function must return the coordinates at which the input must be interpolated in - {input_coordinates}. The rank of the input and output arrays are - given by {input_rank} and {output_rank} respectively. + *input_coordinates*. The rank of the input and output arrays are + given by *input_rank* and *output_rank* respectively. From scipy-svn at scipy.org Sat Dec 20 06:21:33 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 20 Dec 2008 05:21:33 -0600 (CST) Subject: [Scipy-svn] r5282 - trunk/doc/source/tutorial Message-ID: <20081220112133.BCB0EC7C042@scipy.org> Author: david.warde-farley Date: 2008-12-20 05:21:30 -0600 (Sat, 20 Dec 2008) New Revision: 5282 Modified: trunk/doc/source/tutorial/index.rst trunk/doc/source/tutorial/ndimage.rst Log: Eliminated {} around True, False, and None; fixed obvious misspellings, and added ndimage to index.rst. Modified: trunk/doc/source/tutorial/index.rst =================================================================== --- trunk/doc/source/tutorial/index.rst 2008-12-20 11:05:15 UTC (rev 5281) +++ trunk/doc/source/tutorial/index.rst 2008-12-20 11:21:30 UTC (rev 5282) @@ -16,4 +16,4 @@ signal linalg stats - + ndimage Modified: trunk/doc/source/tutorial/ndimage.rst =================================================================== --- trunk/doc/source/tutorial/ndimage.rst 2008-12-20 11:05:15 UTC (rev 5281) +++ trunk/doc/source/tutorial/ndimage.rst 2008-12-20 11:21:30 UTC (rev 5282) @@ -1,5 +1,5 @@ Multi-dimensional image processing (:mod:`ndimage`) -========================================================= +=================================================== .. moduleauthor:: Peter Verveer @@ -326,8 +326,8 @@ {derivative2(input, axis, output, mode, cval, \*extra_arguments, \*\*extra_keywords)} It should calculate the second derivative along the dimension - *axis*. If *output* is not {None} it should use that for the output - and return {None}, otherwise it should return the result. *mode*, + *axis*. If *output* is not None it should use that for the output + and return None, otherwise it should return the result. *mode*, *cval* have the usual meaning. The *extra_arguments* and *extra_keywords* arguments can be used @@ -409,8 +409,8 @@ {derivative(input, axis, output, mode, cval, \*extra_arguments, \*\*extra_keywords)} It should calculate the derivative along the dimension *axis*. If - *output* is not {None} it should use that for the output and return - {None}, otherwise it should return the result. *mode*, *cval* have + *output* is not None it should use that for the output and return + None, otherwise it should return the result. *mode*, *cval* have the usual meaning. The *extra_arguments* and *extra_keywords* arguments can be used @@ -596,9 +596,9 @@ These functions iterate over the lines or elements starting at the -last axis, i.e. the last index changest the fastest. This order of -iteration is garantueed for the case that it is important to adapt -the filter dependening on spatial location. Here is an example of +last axis, i.e. the last index changes the fastest. This order of +iteration is guaranteed for the case that it is important to adapt +the filter depending on spatial location. Here is an example of using a class that implements the filter and keeps track of the current coordinates while iterating. It performs the same filter operation as described above for :func:`generic_filter`, but @@ -747,7 +747,7 @@ The interpolation functions described in section :ref:`ndimage-interpolation` apply pre-filtering by calling :func:`spline_filter`, but they can be instructed not to do this by -setting the *prefilter* keyword equal to {False}. This is useful if +setting the *prefilter* keyword equal to False. This is useful if more than one interpolation operation is done on the same array. In this case it is more efficient to do the pre-filtering only once and use a prefiltered array as the input of the interpolation @@ -1002,7 +1002,7 @@ dilations must be achieved with the iterated structure. The adapted origin is simply obtained by multiplying with the number of iterations. For convenience the :func:`iterate_structure` also returns - the adapted origin if the *origin* parameter is not {None}: + the adapted origin if the *origin* parameter is not None: :: @@ -1058,7 +1058,7 @@ logical *not* of the input with the second structure, followed by the logical *and* of these two erosions. The origin parameters control the placement of the structuring elements as described in - section :ref:`ndimage-filter-functions`. If {origin2} equals {None} it + section :ref:`ndimage-filter-functions`. If {origin2} equals None it is set equal to the {origin1} parameter. If the first structuring element is not provided, a structuring element with connectivity equal to one is generated using :func:`generate_binary_structure`, if @@ -1464,7 +1464,7 @@ :func:`find_objects` returns slices for all objects, unless the *max_label* parameter is larger then zero, in which case only the first *max_label* objects are returned. If an index is missing in - the *label* array, {None} is return instead of a slice. For + the *label* array, None is return instead of a slice. For example: :: @@ -1524,7 +1524,7 @@ The measurement functions described below all support the *index* parameter to indicate which object(s) should be measured. The -default value of *index* is {None}. This indicates that all +default value of *index* is None. This indicates that all elements where the label is larger than zero should be treated as a single object and measured. Thus, in this case the *labels* array is treated as a mask defined by the elements that are larger than @@ -1536,70 +1536,70 @@ The :func:`sum` function calculates the sum of the elements of the object with label(s) given by *index*, using the *labels* array for the - object labels. If *index* is {None}, all elements with a non-zero - label value are treated as a single object. If *label* is {None}, + object labels. If *index* is None, all elements with a non-zero + label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. The :func:`mean` function calculates the mean of the elements of the object with label(s) given by *index*, using the *labels* array for - the object labels. If *index* is {None}, all elements with a + the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is - {None}, all elements of *input* are used in the calculation. + None, all elements of *input* are used in the calculation. The :func:`variance` function calculates the variance of the elements of the object with label(s) given by *index*, using the *labels* array - for the object labels. If *index* is {None}, all elements with a + for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is - {None}, all elements of *input* are used in the calculation. + None, all elements of *input* are used in the calculation. The :func:`standard_deviation` function calculates the standard deviation of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* - is {None}, all elements with a non-zero label value are treated as - a single object. If *label* is {None}, all elements of *input* are + is None, all elements with a non-zero label value are treated as + a single object. If *label* is None, all elements of *input* are used in the calculation. The :func:`minimum` function calculates the minimum of the elements of the object with label(s) given by *index*, using the *labels* array - for the object labels. If *index* is {None}, all elements with a + for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is - {None}, all elements of *input* are used in the calculation. + None, all elements of *input* are used in the calculation. The :func:`maximum` function calculates the maximum of the elements of the object with label(s) given by *index*, using the *labels* array - for the object labels. If *index* is {None}, all elements with a + for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is - {None}, all elements of *input* are used in the calculation. + None, all elements of *input* are used in the calculation. The :func:`minimum_position` function calculates the position of the minimum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* - is {None}, all elements with a non-zero label value are treated as - a single object. If *label* is {None}, all elements of *input* are + is None, all elements with a non-zero label value are treated as + a single object. If *label* is None, all elements of *input* are used in the calculation. The :func:`maximum_position` function calculates the position of the maximum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* - is {None}, all elements with a non-zero label value are treated as - a single object. If *label* is {None}, all elements of *input* are + is None, all elements with a non-zero label value are treated as + a single object. If *label* is None, all elements of *input* are used in the calculation. The :func:`extrema` function calculates the minimum, the maximum, and their positions, of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If - *index* is {None}, all elements with a non-zero label value are - treated as a single object. If *label* is {None}, all elements of + *index* is None, all elements with a non-zero label value are + treated as a single object. If *label* is None, all elements of *input* are used in the calculation. The result is a tuple giving - the minimum, the maximum, the position of the mininum and the + the minimum, the maximum, the position of the minimum and the postition of the maximum. The result is the same as a tuple formed by the results of the functions *minimum*, *maximum*, *minimum_position*, and *maximum_position* that are described @@ -1608,17 +1608,17 @@ The :func:`center_of_mass` function calculates the center of mass of the of the object with label(s) given by *index*, using the - *labels* array for the object labels. If *index* is {None}, all + *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single - object. If *label* is {None}, all elements of *input* are used in + object. If *label* is None, all elements of *input* are used in the calculation. The :func:`histogram` function calculates a histogram of the of the object with label(s) given by *index*, using the *labels* array for - the object labels. If *index* is {None}, all elements with a + the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is - {None}, all elements of *input* are used in the calculation. + None, all elements of *input* are used in the calculation. Histograms are defined by their minimum (*min*), maximum (*max*) and the number of bins (*bins*). They are returned as one-dimensional arrays of type Int32. From scipy-svn at scipy.org Sat Dec 20 06:53:53 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 20 Dec 2008 05:53:53 -0600 (CST) Subject: [Scipy-svn] r5283 - trunk/doc/source/tutorial Message-ID: <20081220115353.AD3A0C7C026@scipy.org> Author: david.warde-farley Date: 2008-12-20 05:53:50 -0600 (Sat, 20 Dec 2008) New Revision: 5283 Modified: trunk/doc/source/tutorial/ndimage.rst Log: Yet more markup cleanup, :obj: is now used where functions are introduced and currentmodule:: has been introduced so as to enable cross-references to generated docs. Modified: trunk/doc/source/tutorial/ndimage.rst =================================================================== --- trunk/doc/source/tutorial/ndimage.rst 2008-12-20 11:21:30 UTC (rev 5282) +++ trunk/doc/source/tutorial/ndimage.rst 2008-12-20 11:53:50 UTC (rev 5283) @@ -5,7 +5,6 @@ .. currentmodule:: scipy.ndimage - .. _ndimage-introduction: Introduction @@ -58,6 +57,8 @@ Filter functions ---------------- +.. currentmodule:: scipy.ndimage.filters + The functions described in this section all perform some type of spatial filtering of the the input array: the elements in the output are some function of the values in the neighborhood of the corresponding input element. We refer to this neighborhood of elements as the filter kernel, which is often rectangular in shape but may also have an arbitrary footprint. Many of the functions described below allow you to define the footprint @@ -139,7 +140,7 @@ "constant" Use a constant value, default is 0.0 [1 2 3]->[0 1 2 3 0] ========== ==================================== ==================== -The {"constant"} mode is special since it needs an additional +The "constant" mode is special since it needs an additional parameter to specify the constant value that should be used. {The easiest way to implement such boundary conditions would be to @@ -152,17 +153,17 @@ Correlation and convolution --------------------------- - The :func:`correlate1d` function calculates a one-dimensional correlation + The :obj:`correlate1d` function calculates a one-dimensional correlation along the given axis. The lines of the array along the given axis are correlated with the given *weights*. The *weights* parameter must be a one-dimensional sequences of numbers. - The function :func:`correlate` implements multi-dimensional correlation + The function :obj:`correlate` implements multi-dimensional correlation of the input array with a given kernel. - The :func:`convolve1d` function calculates a one-dimensional convolution + The :obj:`convolve1d` function calculates a one-dimensional convolution along the given axis. The lines of the array along the given axis are convoluted with the given *weights*. The *weights* parameter must be a one-dimensional sequences of numbers. @@ -172,7 +173,7 @@ in the case of a correlation: the result is shifted in the opposite directions.} - The function :func:`convolve` implements multi-dimensional convolution of + The function :obj:`convolve` implements multi-dimensional convolution of the input array with a given kernel. {A convolution is essentially a correlation after mirroring the @@ -186,7 +187,7 @@ ----------------- - The :func:`gaussian_filter1d` function implements a one-dimensional + The :obj:`gaussian_filter1d` function implements a one-dimensional Gaussian filter. The standard-deviation of the Gaussian filter is passed through the parameter *sigma*. Setting *order* = 0 corresponds to convolution with a Gaussian kernel. An order of 1, 2, or 3 @@ -195,7 +196,7 @@ implemented. - The :func:`gaussian_filter` function implements a multi-dimensional + The :obj:`gaussian_filter` function implements a multi-dimensional Gaussian filter. The standard-deviations of the Gaussian filter along each axis are passed through the parameter *sigma* as a sequence or numbers. If *sigma* is not a sequence but a single @@ -216,11 +217,11 @@ prevented by specifying a more precise output type.} - The :func:`uniform_filter1d` function calculates a one-dimensional + The :obj:`uniform_filter1d` function calculates a one-dimensional uniform filter of the given *size* along the given axis. - The :func:`uniform_filter` implements a multi-dimensional uniform + The :obj:`uniform_filter` implements a multi-dimensional uniform filter. The sizes of the uniform filter are given for each axis as a sequence of integers by the *size* parameter. If *size* is not a sequence, but a single number, the sizes along all axis are assumed @@ -238,15 +239,15 @@ Filters based on order statistics --------------------------------- - The :func:`minimum_filter1d` function calculates a one-dimensional + The :obj:`minimum_filter1d` function calculates a one-dimensional minimum filter of given *size* along the given axis. - The :func:`maximum_filter1d` function calculates a one-dimensional + The :obj:`maximum_filter1d` function calculates a one-dimensional maximum filter of given *size* along the given axis. - The :func:`minimum_filter` function calculates a multi-dimensional + The :obj:`minimum_filter` function calculates a multi-dimensional minimum filter. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which @@ -255,7 +256,7 @@ shape of the kernel by its non-zero elements. - The :func:`maximum_filter` function calculates a multi-dimensional + The :obj:`maximum_filter` function calculates a multi-dimensional maximum filter. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which @@ -264,8 +265,8 @@ shape of the kernel by its non-zero elements. - The :func:`rank_filter` function calculates a multi-dimensional rank - filter. The *rank* may be less then zero, i.e., *rank* =-1 indicates + The :obj:`rank_filter` function calculates a multi-dimensional rank + filter. The *rank* may be less then zero, i.e., *rank* = -1 indicates the largest element. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in @@ -274,9 +275,9 @@ the shape of the kernel by its non-zero elements. - The :func:`percentile_filter` function calculates a multi-dimensional + The :obj:`percentile_filter` function calculates a multi-dimensional percentile filter. The *percentile* may be less then zero, i.e., - *percentile* =-20 equals *percentile* =80. Either the sizes of a + *percentile* = -20 equals *percentile* = 80. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be @@ -285,7 +286,7 @@ elements. - The :func:`median_filter` function calculates a multi-dimensional median + The :obj:`median_filter` function calculates a multi-dimensional median filter. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the @@ -298,16 +299,16 @@ ----------- Derivative filters can be constructed in several ways. The function -{gaussian_filter1d} described in section +:func:`gaussian_filter1d` described in section :ref:`ndimage-filter-functions-smoothing` can be used to calculate derivatives along a given axis using the *order* parameter. Other derivative filters are the Prewitt and Sobel filters: - The :func:`prewitt` function calculates a derivative along the given + The :obj:`prewitt` function calculates a derivative along the given axis. - The :func:`sobel` function calculates a derivative along the given + The :obj:`sobel` function calculates a derivative along the given axis. @@ -318,13 +319,17 @@ calculate the second derivative along a given direction and to construct the Laplace filter: - The function :func:`generic_laplace` calculates a laplace filter using + The function :obj:`generic_laplace` calculates a laplace filter using the function passed through :func:`derivative2` to calculate second derivatives. The function :func:`derivative2` should have the following signature: - {derivative2(input, axis, output, mode, cval, \*extra_arguments, \*\*extra_keywords)} + :: + derivative2(input, axis, output, mode, cval, *extra_arguments, **extra_keywords) + + + It should calculate the second derivative along the dimension *axis*. If *output* is not None it should use that for the output and return None, otherwise it should return the result. *mode*, @@ -383,12 +388,12 @@ :func:`generic_laplace` by providing appropriate functions for the second derivative function: - The function :func:`laplace` calculates the Laplace using discrete + The function :obj:`laplace` calculates the Laplace using discrete differentiation for the second derivative (i.e. convolution with {[1, -2, 1]}). - The function :func:`gaussian_laplace` calculates the Laplace using + The function :obj:`gaussian_laplace` calculates the Laplace using :func:`gaussian_filter` to calculate the second derivatives. The standard-deviations of the Gaussian filter along each axis are passed through the parameter *sigma* as a sequence or numbers. If @@ -401,13 +406,16 @@ generic Laplace function there is a :func:`generic_gradient_magnitude` function that calculated the gradient magnitude of an array: - The function :func:`generic_gradient_magnitude` calculates a gradient + The function :obj:`generic_gradient_magnitude` calculates a gradient magnitude using the function passed through :func:`derivative` to - calculate first derivatives. The function :func:`derivative` should have + calculate first derivatives. The function :obj:`derivative` should have the following signature: - {derivative(input, axis, output, mode, cval, \*extra_arguments, \*\*extra_keywords)} + :: + derivative(input, axis, output, mode, cval, *extra_arguments, **extra_keywords) + + It should calculate the derivative along the dimension *axis*. If *output* is not None it should use that for the output and return None, otherwise it should return the result. *mode*, *cval* have @@ -434,12 +442,12 @@ the *extra_arguments* and *extra_keywords* arguments. -The :func:`sobel` and :func:`prewitt` functions fit the required signature and +The :obj:`sobel` and :func:`prewitt` functions fit the required signature and can therefore directly be used with :func:`generic_gradient_magnitude`. The following function implements the gradient magnitude using Gaussian derivatives: - The function :func:`gaussian_gradient_magnitude` calculates the + The function :obj:`gaussian_gradient_magnitude` calculates the gradient magnitude using :func:`gaussian_filter` to calculate the first derivatives. The standard-deviations of the Gaussian filter along each axis are passed through the parameter *sigma* as a sequence or @@ -461,10 +469,10 @@ also be written in C and passed using a CObject (see :ref:`ndimage-ccallbacks` for more information). - The :func:`generic_filter1d` function implements a generic + The :obj:`generic_filter1d` function implements a generic one-dimensional filter function, where the actual filtering operation must be supplied as a python function (or other callable - object). The :func:`generic_filter1d` function iterates over the lines + object). The :obj:`generic_filter1d` function iterates over the lines of an array and calls :func:`function` at each line. The arguments that are passed to :func:`function` are one-dimensional arrays of the {tFloat64} type. The first contains the values of the current line. @@ -525,9 +533,9 @@ [51 56 62 65]] - The :func:`generic_filter` function implements a generic filter + The :obj:`generic_filter` function implements a generic filter function, where the actual filtering operation must be supplied as - a python function (or other callable object). The :func:`generic_filter` + a python function (or other callable object). The :obj:`generic_filter` function iterates over the array and calls :func:`function` at each element. The argument of :func:`function` is a one-dimensional array of the {tFloat64} type, that contains the values around the current @@ -708,26 +716,26 @@ transform. The parameter *axis* can be used to indicate along which axis the real transform was executed. - The :func:`fourier_shift` function multiplies the input array with the + The :obj:`fourier_shift` function multiplies the input array with the multi-dimensional Fourier transform of a shift operation for the given shift. The *shift* parameter is a sequences of shifts for each dimension, or a single value for all dimensions. - The :func:`fourier_gaussian` function multiplies the input array with + The :obj:`fourier_gaussian` function multiplies the input array with the multi-dimensional Fourier transform of a Gaussian filter with given standard-deviations *sigma*. The *sigma* parameter is a sequences of values for each dimension, or a single value for all dimensions. - The :func:`fourier_uniform` function multiplies the input array with the + The :obj:`fourier_uniform` function multiplies the input array with the multi-dimensional Fourier transform of a uniform filter with given sizes *size*. The *size* parameter is a sequences of values for each dimension, or a single value for all dimensions. - The :func:`fourier_ellipsoid` function multiplies the input array with + The :obj:`fourier_ellipsoid` function multiplies the input array with the multi-dimensional Fourier transform of a elliptically shaped filter with given sizes *size*. The *size* parameter is a sequences of values for each dimension, or a single value for all dimensions. @@ -735,9 +743,14 @@ only implemented for dimensions 1, 2, and 3.} +.. _ndimage-interpolation: + Interpolation functions ----------------------- +.. currentmodule:: scipy.ndimage.interpolation + + This section describes various interpolation functions that are based on B-spline theory. A good introduction to B-splines can be found in: M. Unser, "Splines: A Perfect Fit for Signal and Image @@ -754,13 +767,13 @@ functions. The following two functions implement the pre-filtering: - The :func:`spline_filter1d` function calculates a one-dimensional spline + The :obj:`spline_filter1d` function calculates a one-dimensional spline filter along the given axis. An output array can optionally be provided. The order of the spline must be larger then 1 and less than 6. - The :func:`spline_filter` function calculates a multi-dimensional spline + The :obj:`spline_filter` function calculates a multi-dimensional spline filter. {The multi-dimensional filter is implemented as a sequence of @@ -771,8 +784,6 @@ This can be prevented by specifying a output type of high precision.} -.. _ndimage-interpolation: - Interpolation functions ----------------------- @@ -786,7 +797,7 @@ a *cval* parameter that gives a constant value in case that the {'constant'} mode is used. - The :func:`geometric_transform` function applies an arbitrary geometric + The :obj:`geometric_transform` function applies an arbitrary geometric transform to the input. The given *mapping* function is called at each point in the output to find the corresponding coordinates in the input. *mapping* must be a callable object that accepts a tuple @@ -840,7 +851,7 @@ {The mapping function can also be written in C and passed using a CObject. See :ref:`ndimage-ccallbacks` for more information.} - The function :func:`map_coordinates` applies an arbitrary coordinate + The function :obj:`map_coordinates` applies an arbitrary coordinate transformation using the given array of coordinates. The shape of the output is derived from that of the coordinate array by dropping the first axis. The parameter *coordinates* is used to find for @@ -865,7 +876,7 @@ [ 1.3625 7. ] - The :func:`affine_transform` function applies an affine transformation + The :obj:`affine_transform` function applies an affine transformation to the input array. The given transformation *matrix* and *offset* are used to find for each point in the output the corresponding coordinates in the input. The value of the input at the calculated @@ -879,15 +890,15 @@ shape and type. - The :func:`shift` function returns a shifted version of the input, using + The :obj:`shift` function returns a shifted version of the input, using spline interpolation of the requested *order*. - The :func:`zoom` function returns a rescaled version of the input, using + The :obj:`zoom` function returns a rescaled version of the input, using spline interpolation of the requested *order*. - The :func:`rotate` function returns the input array rotated in the plane + The :obj:`rotate` function returns the input array rotated in the plane defined by the two axes given by the parameter *axes*, using spline interpolation of the requested *order*. The angle must be given in degrees. If *reshape* is true, then the size of the output array is @@ -899,7 +910,7 @@ Binary morphology ----------------- - The :func:`generate_binary_structure` functions generates a binary + The :obj:`generate_binary_structure` functions generates a binary structuring element for use in binary morphology operations. The *rank* of the structure must be provided. The size of the structure that is returned is equal to three in each direction. The value of @@ -923,7 +934,7 @@ Most binary morphology functions can be expressed in terms of the basic operations erosion and dilation: - The :func:`binary_erosion` function implements binary erosion of arrays + The :obj:`binary_erosion` function implements binary erosion of arrays of arbitrary rank with the given structuring element. The origin parameter controls the placement of the structuring element as described in section :ref:`ndimage-filter-functions`. If no @@ -937,7 +948,7 @@ are modified at each iteration. - The :func:`binary_dilation` function implements binary dilation of + The :obj:`binary_dilation` function implements binary dilation of arrays of arbitrary rank with the given structuring element. The origin parameter controls the placement of the structuring element as described in section :ref:`ndimage-filter-functions`. If no @@ -970,15 +981,15 @@ [0 0 0 0 0]] -The :func:`binary_erosion` and :func:`binary_dilation` functions both have an +The :obj:`binary_erosion` and :func:`binary_dilation` functions both have an *iterations* parameter which allows the erosion or dilation to be repeated a number of times. Repeating an erosion or a dilation with a given structure *n* times is equivalent to an erosion or a -dilation with a structure that is {n-1} times dilated with itself. +dilation with a structure that is *n-1* times dilated with itself. A function is provided that allows the calculation of a structure that is dilated a number of times with itself: - The :func:`iterate_structure` function returns a structure by dilation + The :obj:`iterate_structure` function returns a structure by dilation of the input structure *iteration* - 1 times with itself. For instance: @@ -1018,7 +1029,7 @@ d dilation. Following functions provide a few of these operations for convenience: - The :func:`binary_opening` function implements binary opening of arrays + The :obj:`binary_opening` function implements binary opening of arrays of arbitrary rank with the given structuring element. Binary opening is equivalent to a binary erosion followed by a binary dilation with the same structuring element. The origin parameter @@ -1030,7 +1041,7 @@ number of dilations. - The :func:`binary_closing` function implements binary closing of arrays + The :obj:`binary_closing` function implements binary closing of arrays of arbitrary rank with the given structuring element. Binary closing is equivalent to a binary dilation followed by a binary erosion with the same structuring element. The origin parameter @@ -1042,7 +1053,7 @@ same number of erosions. - The :func:`binary_fill_holes` function is used to close holes in + The :obj:`binary_fill_holes` function is used to close holes in objects in a binary image, where the structure defines the connectivity of the holes. The origin parameter controls the placement of the structuring element as described in section @@ -1051,19 +1062,19 @@ using :func:`generate_binary_structure`. - The :func:`binary_hit_or_miss` function implements a binary + The :obj:`binary_hit_or_miss` function implements a binary hit-or-miss transform of arrays of arbitrary rank with the given structuring elements. The hit-or-miss transform is calculated by erosion of the input with the first structure, erosion of the logical *not* of the input with the second structure, followed by the logical *and* of these two erosions. The origin parameters control the placement of the structuring elements as described in - section :ref:`ndimage-filter-functions`. If {origin2} equals None it - is set equal to the {origin1} parameter. If the first structuring + section :ref:`ndimage-filter-functions`. If *origin2* equals None it + is set equal to the *origin1* parameter. If the first structuring element is not provided, a structuring element with connectivity equal to one is generated using :func:`generate_binary_structure`, if - {structure2} is not provided, it is set equal to the logical *not* - of {structure1}. + *structure2* is not provided, it is set equal to the logical *not* + of *structure1*. .. _ndimage-grey-morphology: @@ -1098,45 +1109,45 @@ Similar to binary erosion and dilation there are operations for grey-scale erosion and dilation: - The :func:`grey_erosion` function calculates a multi-dimensional grey- + The :obj:`grey_erosion` function calculates a multi-dimensional grey- scale erosion. - The :func:`grey_dilation` function calculates a multi-dimensional grey- + The :obj:`grey_dilation` function calculates a multi-dimensional grey- scale dilation. Grey-scale opening and closing operations can be defined similar to their binary counterparts: - The :func:`grey_opening` function implements grey-scale opening of + The :obj:`grey_opening` function implements grey-scale opening of arrays of arbitrary rank. Grey-scale opening is equivalent to a grey-scale erosion followed by a grey-scale dilation. - The :func:`grey_closing` function implements grey-scale closing of + The :obj:`grey_closing` function implements grey-scale closing of arrays of arbitrary rank. Grey-scale opening is equivalent to a grey-scale dilation followed by a grey-scale erosion. - The :func:`morphological_gradient` function implements a grey-scale + The :obj:`morphological_gradient` function implements a grey-scale morphological gradient of arrays of arbitrary rank. The grey-scale morphological gradient is equal to the difference of a grey-scale dilation and a grey-scale erosion. - The :func:`morphological_laplace` function implements a grey-scale + The :obj:`morphological_laplace` function implements a grey-scale morphological laplace of arrays of arbitrary rank. The grey-scale morphological laplace is equal to the sum of a grey-scale dilation and a grey-scale erosion minus twice the input. - The :func:`white_tophat` function implements a white top-hat filter of + The :obj:`white_tophat` function implements a white top-hat filter of arrays of arbitrary rank. The white top-hat is equal to the difference of the input and a grey-scale opening. - The :func:`black_tophat` function implements a black top-hat filter of + The :obj:`black_tophat` function implements a black top-hat filter of arrays of arbitrary rank. The black top-hat is equal to the difference of the a grey-scale closing and the input. @@ -1146,13 +1157,15 @@ Distance transforms ------------------- +.. currentmodule:: scipy.ndimage.morphology + Distance transforms are used to calculate the minimum distance from each element of an object to the background. The following functions implement distance transforms for three different distance metrics: Euclidean, City Block, and Chessboard distances. - The function :func:`distance_transform_cdt` uses a chamfer type + The function :obj:`distance_transform_cdt` uses a chamfer type algorithm to calculate the distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest distance to the background (all non-object @@ -1182,7 +1195,7 @@ 27:321-345, 1984. - The function :func:`distance_transform_edt` calculates the exact + The function :obj:`distance_transform_edt` calculates the exact euclidean distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest euclidean distance to the background (all non-object elements). @@ -1209,12 +1222,12 @@ in arbitrary dimensions. IEEE Trans. PAMI 25, 265-270, 2003. - The function :func:`distance_transform_bf` uses a brute-force algorithm + The function :obj:`distance_transform_bf` uses a brute-force algorithm to calculate the distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest distance to the background (all non-object elements). The - metric must be one of {"euclidean"}, {"cityblock"}, or - {"chessboard"}. + metric must be one of "euclidean", "cityblock", or + "chessboard". In addition to the distance transform, the feature transform can be calculated. In this case the index of the closest background @@ -1260,10 +1273,10 @@ [0 0 0 0 1 0]] The result is a binary image, in which the individual objects still -need to be identified and labeled. The function :func:`label` generates +need to be identified and labeled. The function :obj:`label` generates an array where each object is assigned a unique number: - The :func:`label` function generates an array where the objects in the + The :obj:`label` function generates an array where the objects in the input are labeled with an integer index. It returns a tuple consisting of the array of object labels and the number of objects found, unless the *output* parameter is given, in which case only @@ -1323,13 +1336,13 @@ There is a large number of other approaches for segmentation, for instance from an estimation of the borders of the objects that can be obtained for instance by derivative filters. One such an -approach is watershed segmentation. The function :func:`watershed_ift` +approach is watershed segmentation. The function :obj:`watershed_ift` generates an array where each object is assigned a unique label, from an array that localizes the object borders, generated for instance by a gradient magnitude filter. It uses an array containing initial markers for the objects: - The :func:`watershed_ift` function applies a watershed from markers + The :obj:`watershed_ift` function applies a watershed from markers algorithm, using an Iterative Forest Transform, as described in: P. Felkel, R. Wegenkittl, and M. Bruckschwaiger, "Implementation and Complexity of the Watershed-from-Markers Algorithm Computed as a @@ -1364,8 +1377,8 @@ [1 1 2 2 2 1 1] [1 1 1 1 1 1 1]] - Here two markers were used to designate an object (marker=2) and - the background (marker=1). The order in which these are processed + Here two markers were used to designate an object (*marker* = 2) and + the background (*marker* = 1). The order in which these are processed is arbitrary: moving the marker for the background to the lower right corner of the array yields a different result: @@ -1387,7 +1400,7 @@ [1 1 1 1 1 1 1] [1 1 1 1 1 1 1]] - The result is that the object (marker=2) is smaller because the + The result is that the object (*marker* = 2) is smaller because the second marker was processed earlier. This may not be the desired effect if the first marker was supposed to designate a background object. Therefore :func:`watershed_ift` treats markers with a negative @@ -1436,15 +1449,19 @@ of the input to \\constant{UInt8} and \\constant{UInt16}.} +.. _ndimage-object-measurements: + Object measurements ------------------- +.. currentmodule:: scipy.ndimage.measurements + Given an array of labeled objects, the properties of the individual -objects can be measured. The :func:`find_objects` function can be used +objects can be measured. The :obj:`find_objects` function can be used to generate a list of slices that for each object, give the smallest sub-array that fully contains the object: - The :func:`find_objects` function finds all objects in a labeled array and + The :obj:`find_objects` function finds all objects in a labeled array and returns a list of slices that correspond to the smallest regions in the array that contains the object. For instance: @@ -1534,28 +1551,28 @@ one result, return their result as a tuple if *index* is a single number, or as a tuple of lists, if *index* is a sequence. - The :func:`sum` function calculates the sum of the elements of the object + The :obj:`sum` function calculates the sum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :func:`mean` function calculates the mean of the elements of the + The :obj:`mean` function calculates the mean of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :func:`variance` function calculates the variance of the elements of + The :obj:`variance` function calculates the variance of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :func:`standard_deviation` function calculates the standard + The :obj:`standard_deviation` function calculates the standard deviation of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as @@ -1563,21 +1580,21 @@ used in the calculation. - The :func:`minimum` function calculates the minimum of the elements of + The :obj:`minimum` function calculates the minimum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :func:`maximum` function calculates the maximum of the elements of + The :obj:`maximum` function calculates the maximum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :func:`minimum_position` function calculates the position of the + The :obj:`minimum_position` function calculates the position of the minimum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as @@ -1585,7 +1602,7 @@ used in the calculation. - The :func:`maximum_position` function calculates the position of the + The :obj:`maximum_position` function calculates the position of the maximum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as @@ -1593,7 +1610,7 @@ used in the calculation. - The :func:`extrema` function calculates the minimum, the maximum, and + The :obj:`extrema` function calculates the minimum, the maximum, and their positions, of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are @@ -1606,7 +1623,7 @@ above. - The :func:`center_of_mass` function calculates the center of mass of + The :obj:`center_of_mass` function calculates the center of mass of the of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single @@ -1614,7 +1631,7 @@ the calculation. - The :func:`histogram` function calculates a histogram of the of the + The :obj:`histogram` function calculates a histogram of the of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is @@ -1626,10 +1643,10 @@ .. _ndimage-ccallbacks: -Extending *ndimage* in C -------------------------- +Extending :mod:`ndimage` in C +----------------------------- -{C callback functions} A few functions in the {numarray.ndimage} take a call-back argument. This can be a python function, but also a CObject containing a pointer to a C function. To use this feature, you must write your own C extension that defines the function, and define a python function that +A few functions in the :mod:`scipy.ndimage` take a call-back argument. This can be a python function, but also a CObject containing a pointer to a C function. To use this feature, you must write your own C extension that defines the function, and define a python function that returns a CObject containing a pointer to this function. An example of a function that supports this is @@ -1745,7 +1762,7 @@ Functions that support C callback functions ------------------------------------------- -The :func:`ndimage` functions that support C callback functions are +The :mod:`ndimage` functions that support C callback functions are described here. Obviously, the prototype of the function that is provided to these functions must match exactly that what they expect. Therefore we give here the prototypes of the callback @@ -1773,7 +1790,6 @@ calculated valued should be returned in the *return_value* argument. - The function :func:`generic_filter1d` (see section :ref:`ndimage-genericfilters`) accepts a callback function with the following prototype: @@ -1788,7 +1804,6 @@ in the array passed through *output_line*. The length of the output line is passed through *output_length*. - The function :func:`geometric_transform` (see section :ref:`ndimage-interpolation`) expects a function with the following prototype: From scipy-svn at scipy.org Sat Dec 20 08:50:25 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 20 Dec 2008 07:50:25 -0600 (CST) Subject: [Scipy-svn] r5284 - trunk/doc/source/tutorial Message-ID: <20081220135025.4D293C7C026@scipy.org> Author: david.warde-farley Date: 2008-12-20 07:50:20 -0600 (Sat, 20 Dec 2008) New Revision: 5284 Modified: trunk/doc/source/tutorial/ndimage.rst Log: * Cleared up my understanding of :obj: vs. :func:. :func: is the right thing to be using. * Replaced numarray with numpy wherever possible (not in code, though) * Demarcated notes, which were previously just {} enclosed due to markup loss * Got subsubsections working. * Highlighting C code, linking to the Python C API (Sphinx rocks) * Fixed up more crossreferencing stuff... * Fixed a few typos/language errors. * Morphology sub-heading to encompass both Binary and Greyscale, as it was before. * currentmodule directives so that things link like they're supposed to. * Removed "section" from the backreferences as "see section
    " doesn't make much sense, only makes sense if there is a number. Still needs to be verified for parts of the C API that I'm not familiar with, changed over to new C types (Int32 for example, to whatever is in use now). Otherwise I think the import is complete! Modified: trunk/doc/source/tutorial/ndimage.rst =================================================================== --- trunk/doc/source/tutorial/ndimage.rst 2008-12-20 11:53:50 UTC (rev 5283) +++ trunk/doc/source/tutorial/ndimage.rst 2008-12-20 13:50:20 UTC (rev 5284) @@ -14,7 +14,7 @@ two-dimensional arrays of values. There are however a number of fields where images of higher dimensionality must be analyzed. Good examples of these are medical imaging and biological imaging. -:mod:`numarray` is suited very well for this type of applications due +:mod:`numpy` is suited very well for this type of applications due its inherent multi-dimensional nature. The :mod:`scipy.ndimage` packages provides a number of general image processing and analysis functions that are designed to operate with arrays of arbitrary @@ -41,7 +41,7 @@ equal to the type of the specified output argument. If no output argument is given, it is still possible to specify what the result of the output should be. This is done by simply assigning the -desired numarray type object to the output argument. For example: +desired `numpy` type object to the output argument. For example: :: @@ -50,7 +50,7 @@ >>> print correlate(arange(10), [1, 2.5], output = Float64) [ 0. 2.5 6. 9.5 13. 16.5 20. 23.5 27. 30.5] -{In previous versions of :mod:`scipy.ndimage`, some functions accepted the *output_type* argument to achieve the same effect. This argument is still supported, but its use will generate an deprecation warning. In a future version all instances of this argument will be removed. The preferred way to specify an output type, is by using the *output* argument, either by specifying an output array of the desired type, or by specifying the type of the output that is to be returned.} +.. note:: In previous versions of :mod:`scipy.ndimage`, some functions accepted the *output_type* argument to achieve the same effect. This argument is still supported, but its use will generate an deprecation warning. In a future version all instances of this argument will be removed. The preferred way to specify an output type, is by using the *output* argument, either by specifying an output array of the desired type, or by specifying the type of the output that is to be returned. .. _ndimage-filter-functions: @@ -143,51 +143,40 @@ The "constant" mode is special since it needs an additional parameter to specify the constant value that should be used. -{The easiest way to implement such boundary conditions would be to -copy the data to a larger array and extend the data at the borders -according to the boundary conditions. For large arrays and large filter -kernels, this would be very memory consuming, and the functions described -below therefore use a different approach that does not require allocating -large temporary buffers.} +.. note:: The easiest way to implement such boundary conditions would be to copy the data to a larger array and extend the data at the borders according to the boundary conditions. For large arrays and large filter kernels, this would be very memory consuming, and the functions described below therefore use a different approach that does not require allocating large temporary buffers. Correlation and convolution ---------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The :obj:`correlate1d` function calculates a one-dimensional correlation + The :func:`correlate1d` function calculates a one-dimensional correlation along the given axis. The lines of the array along the given axis are correlated with the given *weights*. The *weights* parameter must be a one-dimensional sequences of numbers. - The function :obj:`correlate` implements multi-dimensional correlation + The function :func:`correlate` implements multi-dimensional correlation of the input array with a given kernel. - The :obj:`convolve1d` function calculates a one-dimensional convolution + The :func:`convolve1d` function calculates a one-dimensional convolution along the given axis. The lines of the array along the given axis are convoluted with the given *weights*. The *weights* parameter must be a one-dimensional sequences of numbers. - {A convolution is essentially a correlation after mirroring the - kernel. As a result, the *origin* parameter behaves differently than - in the case of a correlation: the result is shifted in the opposite - directions.} + .. note:: A convolution is essentially a correlation after mirroring the kernel. As a result, the *origin* parameter behaves differently than in the case of a correlation: the result is shifted in the opposite directions. - The function :obj:`convolve` implements multi-dimensional convolution of + The function :func:`convolve` implements multi-dimensional convolution of the input array with a given kernel. - {A convolution is essentially a correlation after mirroring the - kernel. As a result, the *origin* parameter behaves differently than - in the case of a correlation: the results is shifted in the opposite - direction.} + .. note:: A convolution is essentially a correlation after mirroring the kernel. As a result, the *origin* parameter behaves differently than in the case of a correlation: the results is shifted in the opposite direction. .. _ndimage-filter-functions-smoothing: Smoothing filters ------------------ +^^^^^^^^^^^^^^^^^ - The :obj:`gaussian_filter1d` function implements a one-dimensional + The :func:`gaussian_filter1d` function implements a one-dimensional Gaussian filter. The standard-deviation of the Gaussian filter is passed through the parameter *sigma*. Setting *order* = 0 corresponds to convolution with a Gaussian kernel. An order of 1, 2, or 3 @@ -196,7 +185,7 @@ implemented. - The :obj:`gaussian_filter` function implements a multi-dimensional + The :func:`gaussian_filter` function implements a multi-dimensional Gaussian filter. The standard-deviations of the Gaussian filter along each axis are passed through the parameter *sigma* as a sequence or numbers. If *sigma* is not a sequence but a single @@ -209,45 +198,34 @@ number, to specify the same order for all axes, or a sequence of numbers to specify a different order for each axis. - {The multi-dimensional filter is implemented as a sequence of - one-dimensional Gaussian filters. The intermediate arrays are stored in - the same data type as the output. Therefore, for output types with a - lower precision, the results may be imprecise because intermediate - results may be stored with insufficient precision. This can be - prevented by specifying a more precise output type.} + .. note:: The multi-dimensional filter is implemented as a sequence of one-dimensional Gaussian filters. The intermediate arrays are stored in the same data type as the output. Therefore, for output types with a lower precision, the results may be imprecise because intermediate results may be stored with insufficient precision. This can be prevented by specifying a more precise output type. - The :obj:`uniform_filter1d` function calculates a one-dimensional + The :func:`uniform_filter1d` function calculates a one-dimensional uniform filter of the given *size* along the given axis. - The :obj:`uniform_filter` implements a multi-dimensional uniform + The :func:`uniform_filter` implements a multi-dimensional uniform filter. The sizes of the uniform filter are given for each axis as a sequence of integers by the *size* parameter. If *size* is not a sequence, but a single number, the sizes along all axis are assumed to be equal. - {The multi-dimensional filter is implemented as a sequence of - one-dimensional uniform filters. The intermediate arrays are stored in - the same data type as the output. Therefore, for output types with a - lower precision, the results may be imprecise because intermediate - results may be stored with insufficient precision. This can be - prevented by specifying a - more precise output type.} + .. note:: The multi-dimensional filter is implemented as a sequence of one-dimensional uniform filters. The intermediate arrays are stored in the same data type as the output. Therefore, for output types with a lower precision, the results may be imprecise because intermediate results may be stored with insufficient precision. This can be prevented by specifying a more precise output type. Filters based on order statistics ---------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The :obj:`minimum_filter1d` function calculates a one-dimensional + The :func:`minimum_filter1d` function calculates a one-dimensional minimum filter of given *size* along the given axis. - The :obj:`maximum_filter1d` function calculates a one-dimensional + The :func:`maximum_filter1d` function calculates a one-dimensional maximum filter of given *size* along the given axis. - The :obj:`minimum_filter` function calculates a multi-dimensional + The :func:`minimum_filter` function calculates a multi-dimensional minimum filter. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which @@ -256,7 +234,7 @@ shape of the kernel by its non-zero elements. - The :obj:`maximum_filter` function calculates a multi-dimensional + The :func:`maximum_filter` function calculates a multi-dimensional maximum filter. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which @@ -265,7 +243,7 @@ shape of the kernel by its non-zero elements. - The :obj:`rank_filter` function calculates a multi-dimensional rank + The :func:`rank_filter` function calculates a multi-dimensional rank filter. The *rank* may be less then zero, i.e., *rank* = -1 indicates the largest element. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, @@ -275,7 +253,7 @@ the shape of the kernel by its non-zero elements. - The :obj:`percentile_filter` function calculates a multi-dimensional + The :func:`percentile_filter` function calculates a multi-dimensional percentile filter. The *percentile* may be less then zero, i.e., *percentile* = -20 equals *percentile* = 80. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. @@ -286,7 +264,7 @@ elements. - The :obj:`median_filter` function calculates a multi-dimensional median + The :func:`median_filter` function calculates a multi-dimensional median filter. Either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The *size* parameter, if provided, must be a sequence of sizes or a single number in which case the @@ -296,19 +274,19 @@ Derivatives ------------ +^^^^^^^^^^^ Derivative filters can be constructed in several ways. The function -:func:`gaussian_filter1d` described in section +:func:`gaussian_filter1d` described in :ref:`ndimage-filter-functions-smoothing` can be used to calculate derivatives along a given axis using the *order* parameter. Other derivative filters are the Prewitt and Sobel filters: - The :obj:`prewitt` function calculates a derivative along the given + The :func:`prewitt` function calculates a derivative along the given axis. - The :obj:`sobel` function calculates a derivative along the given + The :func:`sobel` function calculates a derivative along the given axis. @@ -319,7 +297,7 @@ calculate the second derivative along a given direction and to construct the Laplace filter: - The function :obj:`generic_laplace` calculates a laplace filter using + The function :func:`generic_laplace` calculates a laplace filter using the function passed through :func:`derivative2` to calculate second derivatives. The function :func:`derivative2` should have the following signature: @@ -388,12 +366,12 @@ :func:`generic_laplace` by providing appropriate functions for the second derivative function: - The function :obj:`laplace` calculates the Laplace using discrete + The function :func:`laplace` calculates the Laplace using discrete differentiation for the second derivative (i.e. convolution with - {[1, -2, 1]}). + :obj:`[1, -2, 1]`). - The function :obj:`gaussian_laplace` calculates the Laplace using + The function :func:`gaussian_laplace` calculates the Laplace using :func:`gaussian_filter` to calculate the second derivatives. The standard-deviations of the Gaussian filter along each axis are passed through the parameter *sigma* as a sequence or numbers. If @@ -406,9 +384,9 @@ generic Laplace function there is a :func:`generic_gradient_magnitude` function that calculated the gradient magnitude of an array: - The function :obj:`generic_gradient_magnitude` calculates a gradient + The function :func:`generic_gradient_magnitude` calculates a gradient magnitude using the function passed through :func:`derivative` to - calculate first derivatives. The function :obj:`derivative` should have + calculate first derivatives. The function :func:`derivative` should have the following signature: :: @@ -442,12 +420,12 @@ the *extra_arguments* and *extra_keywords* arguments. -The :obj:`sobel` and :func:`prewitt` functions fit the required signature and +The :func:`sobel` and :func:`prewitt` functions fit the required signature and can therefore directly be used with :func:`generic_gradient_magnitude`. The following function implements the gradient magnitude using Gaussian derivatives: - The function :obj:`gaussian_gradient_magnitude` calculates the + The function :func:`gaussian_gradient_magnitude` calculates the gradient magnitude using :func:`gaussian_filter` to calculate the first derivatives. The standard-deviations of the Gaussian filter along each axis are passed through the parameter *sigma* as a sequence or @@ -458,7 +436,7 @@ .. _ndimage-genericfilters: Generic filter functions ------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^ To implement filter functions, generic functions can be used that accept a callable object that implements the filtering operation. The iteration over the @@ -466,16 +444,16 @@ details as the implementation of the boundary conditions. Only a callable object implementing a callback function that does the actual filtering work must be provided. The callback function can -also be written in C and passed using a CObject (see +also be written in C and passed using a :ctype:`PyCObject` (see :ref:`ndimage-ccallbacks` for more information). - The :obj:`generic_filter1d` function implements a generic + The :func:`generic_filter1d` function implements a generic one-dimensional filter function, where the actual filtering operation must be supplied as a python function (or other callable - object). The :obj:`generic_filter1d` function iterates over the lines + object). The :func:`generic_filter1d` function iterates over the lines of an array and calls :func:`function` at each line. The arguments that are passed to :func:`function` are one-dimensional arrays of the - {tFloat64} type. The first contains the values of the current line. + :ctype:`tFloat64` type. The first contains the values of the current line. It is extended at the beginning end the end, according to the *filter_size* and *origin* arguments. The second array should be modified in-place to provide the output values of the line. For @@ -533,12 +511,12 @@ [51 56 62 65]] - The :obj:`generic_filter` function implements a generic filter + The :func:`generic_filter` function implements a generic filter function, where the actual filtering operation must be supplied as - a python function (or other callable object). The :obj:`generic_filter` + a python function (or other callable object). The :func:`generic_filter` function iterates over the array and calls :func:`function` at each element. The argument of :func:`function` is a one-dimensional array of - the {tFloat64} type, that contains the values around the current + the :ctype:`tFloat64` type, that contains the values around the current element that are within the footprint of the filter. The function should return a single value that can be converted to a double precision number. For example consider a correlation: @@ -698,12 +676,12 @@ [51 56 62 65]] Fourier domain filters ----------------------- +^^^^^^^^^^^^^^^^^^^^^^ The functions described in this section perform filtering operations in the Fourier domain. Thus, the input array of such a function should be compatible with an inverse Fourier transform -function, such as the functions from the {scipy.fft} module. We +function, such as the functions from the :mod:`numpy.fft` module. We therefore have to deal with arrays that may be the result of a real or a complex Fourier transform. In the case of a real Fourier transform only half of the of the symmetric complex transform is @@ -716,31 +694,30 @@ transform. The parameter *axis* can be used to indicate along which axis the real transform was executed. - The :obj:`fourier_shift` function multiplies the input array with the + The :func:`fourier_shift` function multiplies the input array with the multi-dimensional Fourier transform of a shift operation for the given shift. The *shift* parameter is a sequences of shifts for each dimension, or a single value for all dimensions. - The :obj:`fourier_gaussian` function multiplies the input array with + The :func:`fourier_gaussian` function multiplies the input array with the multi-dimensional Fourier transform of a Gaussian filter with given standard-deviations *sigma*. The *sigma* parameter is a sequences of values for each dimension, or a single value for all dimensions. - The :obj:`fourier_uniform` function multiplies the input array with the + The :func:`fourier_uniform` function multiplies the input array with the multi-dimensional Fourier transform of a uniform filter with given sizes *size*. The *size* parameter is a sequences of values for each dimension, or a single value for all dimensions. - The :obj:`fourier_ellipsoid` function multiplies the input array with + The :func:`fourier_ellipsoid` function multiplies the input array with the multi-dimensional Fourier transform of a elliptically shaped filter with given sizes *size*. The *size* parameter is a sequences of values for each dimension, or a single value for all dimensions. - {This function is - only implemented for dimensions 1, 2, and 3.} + This function is only implemented for dimensions 1, 2, and 3. .. _ndimage-interpolation: @@ -755,7 +732,12 @@ based on B-spline theory. A good introduction to B-splines can be found in: M. Unser, "Splines: A Perfect Fit for Signal and Image Processing," IEEE Signal Processing Magazine, vol. 16, no. 6, pp. -22-38, November 1999. {Spline pre-filters} Interpolation using +22-38, November 1999. + +Spline pre-filters +^^^^^^^^^^^^^^^^^^ + +Interpolation using splines of an order larger than 1 requires a pre- filtering step. The interpolation functions described in section :ref:`ndimage-interpolation` apply pre-filtering by calling @@ -767,37 +749,32 @@ functions. The following two functions implement the pre-filtering: - The :obj:`spline_filter1d` function calculates a one-dimensional spline + The :func:`spline_filter1d` function calculates a one-dimensional spline filter along the given axis. An output array can optionally be provided. The order of the spline must be larger then 1 and less than 6. - The :obj:`spline_filter` function calculates a multi-dimensional spline + The :func:`spline_filter` function calculates a multi-dimensional spline filter. - {The multi-dimensional filter is implemented as a sequence of - one-dimensional spline filters. The intermediate arrays are stored in - the same data type as the output. Therefore, if an output - with a limited precision is requested, the results may be imprecise - because intermediate results may be stored with insufficient precision. - This can be prevented by specifying a output type of high precision.} + .. note:: The multi-dimensional filter is implemented as a sequence of one-dimensional spline filters. The intermediate arrays are stored in the same data type as the output. Therefore, if an output with a limited precision is requested, the results may be imprecise because intermediate results may be stored with insufficient precision. This can be prevented by specifying a output type of high precision. Interpolation functions ------------------------ +^^^^^^^^^^^^^^^^^^^^^^^ Following functions all employ spline interpolation to effect some type of geometric transformation of the input array. This requires a mapping of the output coordinates to the input coordinates, and therefore the possibility arises that input values outside the boundaries are needed. This problem is -solved in the same way as described in section :ref:`ndimage-filter-functions` +solved in the same way as described in :ref:`ndimage-filter-functions` for the multi-dimensional filter functions. Therefore these functions all support a *mode* parameter that determines how the boundaries are handled, and -a *cval* parameter that gives a constant value in case that the {'constant'} +a *cval* parameter that gives a constant value in case that the 'constant' mode is used. - The :obj:`geometric_transform` function applies an arbitrary geometric + The :func:`geometric_transform` function applies an arbitrary geometric transform to the input. The given *mapping* function is called at each point in the output to find the corresponding coordinates in the input. *mapping* must be a callable object that accepts a tuple @@ -848,17 +825,17 @@ [ 0. 4.8125 6.1875] [ 0. 8.2625 9.6375]] - {The mapping function can also be written in C and passed using a CObject. See :ref:`ndimage-ccallbacks` for more information.} + .. note:: The mapping function can also be written in C and passed using a :ctype:`PyCObject`. See :ref:`ndimage-ccallbacks` for more information. - The function :obj:`map_coordinates` applies an arbitrary coordinate + The function :func:`map_coordinates` applies an arbitrary coordinate transformation using the given array of coordinates. The shape of the output is derived from that of the coordinate array by dropping the first axis. The parameter *coordinates* is used to find for each point in the output the corresponding coordinates in the input. The values of *coordinates* along the first axis are the coordinates in the input array at which the output value is found. - (See also the numarray *coordinates* function.) Since the + (See also the numarray `coordinates` function.) Since the coordinates may be non- integer coordinates, the value of the input at these coordinates is determined by spline interpolation of the requested order. Here is an example that interpolates a 2D array at @@ -876,7 +853,7 @@ [ 1.3625 7. ] - The :obj:`affine_transform` function applies an affine transformation + The :func:`affine_transform` function applies an affine transformation to the input array. The given transformation *matrix* and *offset* are used to find for each point in the output the corresponding coordinates in the input. The value of the input at the calculated @@ -890,27 +867,36 @@ shape and type. - The :obj:`shift` function returns a shifted version of the input, using + The :func:`shift` function returns a shifted version of the input, using spline interpolation of the requested *order*. - The :obj:`zoom` function returns a rescaled version of the input, using + The :func:`zoom` function returns a rescaled version of the input, using spline interpolation of the requested *order*. - The :obj:`rotate` function returns the input array rotated in the plane + The :func:`rotate` function returns the input array rotated in the plane defined by the two axes given by the parameter *axes*, using spline interpolation of the requested *order*. The angle must be given in degrees. If *reshape* is true, then the size of the output array is adapted to contain the rotated input. +.. _ndimage-morphology: + +Morphology +---------- + .. _ndimage-binary-morphology: Binary morphology ------------------ +^^^^^^^^^^^^^^^^^ - The :obj:`generate_binary_structure` functions generates a binary +.. currentmodule:: scipy.ndimage.morphology + +Binary morphology (need something to put here). + + The :func:`generate_binary_structure` functions generates a binary structuring element for use in binary morphology operations. The *rank* of the structure must be provided. The size of the structure that is returned is equal to three in each direction. The value of @@ -934,10 +920,10 @@ Most binary morphology functions can be expressed in terms of the basic operations erosion and dilation: - The :obj:`binary_erosion` function implements binary erosion of arrays + The :func:`binary_erosion` function implements binary erosion of arrays of arbitrary rank with the given structuring element. The origin parameter controls the placement of the structuring element as - described in section :ref:`ndimage-filter-functions`. If no + described in :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal to one is generated using :func:`generate_binary_structure`. The *border_value* parameter gives the value of the array outside @@ -948,10 +934,10 @@ are modified at each iteration. - The :obj:`binary_dilation` function implements binary dilation of + The :func:`binary_dilation` function implements binary dilation of arrays of arbitrary rank with the given structuring element. The origin parameter controls the placement of the structuring element - as described in section :ref:`ndimage-filter-functions`. If no + as described in :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal to one is generated using :func:`generate_binary_structure`. The *border_value* parameter gives the value of the array outside @@ -981,7 +967,7 @@ [0 0 0 0 0]] -The :obj:`binary_erosion` and :func:`binary_dilation` functions both have an +The :func:`binary_erosion` and :func:`binary_dilation` functions both have an *iterations* parameter which allows the erosion or dilation to be repeated a number of times. Repeating an erosion or a dilation with a given structure *n* times is equivalent to an erosion or a @@ -989,7 +975,7 @@ A function is provided that allows the calculation of a structure that is dilated a number of times with itself: - The :obj:`iterate_structure` function returns a structure by dilation + The :func:`iterate_structure` function returns a structure by dilation of the input structure *iteration* - 1 times with itself. For instance: @@ -1029,47 +1015,47 @@ d dilation. Following functions provide a few of these operations for convenience: - The :obj:`binary_opening` function implements binary opening of arrays + The :func:`binary_opening` function implements binary opening of arrays of arbitrary rank with the given structuring element. Binary opening is equivalent to a binary erosion followed by a binary dilation with the same structuring element. The origin parameter controls the placement of the structuring element as described in - section :ref:`ndimage-filter-functions`. If no structuring element is + :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal to one is generated using :func:`generate_binary_structure`. The *iterations* parameter gives the number of erosions that is performed followed by the same number of dilations. - The :obj:`binary_closing` function implements binary closing of arrays + The :func:`binary_closing` function implements binary closing of arrays of arbitrary rank with the given structuring element. Binary closing is equivalent to a binary dilation followed by a binary erosion with the same structuring element. The origin parameter controls the placement of the structuring element as described in - section :ref:`ndimage-filter-functions`. If no structuring element is + :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal to one is generated using :func:`generate_binary_structure`. The *iterations* parameter gives the number of dilations that is performed followed by the same number of erosions. - The :obj:`binary_fill_holes` function is used to close holes in + The :func:`binary_fill_holes` function is used to close holes in objects in a binary image, where the structure defines the connectivity of the holes. The origin parameter controls the - placement of the structuring element as described in section + placement of the structuring element as described in :ref:`ndimage-filter-functions`. If no structuring element is provided, an element with connectivity equal to one is generated using :func:`generate_binary_structure`. - The :obj:`binary_hit_or_miss` function implements a binary + The :func:`binary_hit_or_miss` function implements a binary hit-or-miss transform of arrays of arbitrary rank with the given structuring elements. The hit-or-miss transform is calculated by erosion of the input with the first structure, erosion of the logical *not* of the input with the second structure, followed by the logical *and* of these two erosions. The origin parameters control the placement of the structuring elements as described in - section :ref:`ndimage-filter-functions`. If *origin2* equals None it + :ref:`ndimage-filter-functions`. If *origin2* equals None it is set equal to the *origin1* parameter. If the first structuring element is not provided, a structuring element with connectivity equal to one is generated using :func:`generate_binary_structure`, if @@ -1080,13 +1066,15 @@ .. _ndimage-grey-morphology: Grey-scale morphology ---------------------- +^^^^^^^^^^^^^^^^^^^^^ +.. currentmodule:: scipy.ndimage.morphology + Grey-scale morphology operations are the equivalents of binary morphology operations that operate on arrays with arbitrary values. Below we describe the grey-scale equivalents of erosion, dilation, opening and closing. These operations are implemented in a similar -fashion as the filters described in section +fashion as the filters described in :ref:`ndimage-filter-functions`, and we refer to this section for the description of filter kernels and footprints, and the handling of array borders. The grey-scale morphology operations optionally take @@ -1109,45 +1097,45 @@ Similar to binary erosion and dilation there are operations for grey-scale erosion and dilation: - The :obj:`grey_erosion` function calculates a multi-dimensional grey- + The :func:`grey_erosion` function calculates a multi-dimensional grey- scale erosion. - The :obj:`grey_dilation` function calculates a multi-dimensional grey- + The :func:`grey_dilation` function calculates a multi-dimensional grey- scale dilation. Grey-scale opening and closing operations can be defined similar to their binary counterparts: - The :obj:`grey_opening` function implements grey-scale opening of + The :func:`grey_opening` function implements grey-scale opening of arrays of arbitrary rank. Grey-scale opening is equivalent to a grey-scale erosion followed by a grey-scale dilation. - The :obj:`grey_closing` function implements grey-scale closing of + The :func:`grey_closing` function implements grey-scale closing of arrays of arbitrary rank. Grey-scale opening is equivalent to a grey-scale dilation followed by a grey-scale erosion. - The :obj:`morphological_gradient` function implements a grey-scale + The :func:`morphological_gradient` function implements a grey-scale morphological gradient of arrays of arbitrary rank. The grey-scale morphological gradient is equal to the difference of a grey-scale dilation and a grey-scale erosion. - The :obj:`morphological_laplace` function implements a grey-scale + The :func:`morphological_laplace` function implements a grey-scale morphological laplace of arrays of arbitrary rank. The grey-scale morphological laplace is equal to the sum of a grey-scale dilation and a grey-scale erosion minus twice the input. - The :obj:`white_tophat` function implements a white top-hat filter of + The :func:`white_tophat` function implements a white top-hat filter of arrays of arbitrary rank. The white top-hat is equal to the difference of the input and a grey-scale opening. - The :obj:`black_tophat` function implements a black top-hat filter of + The :func:`black_tophat` function implements a black top-hat filter of arrays of arbitrary rank. The black top-hat is equal to the difference of the a grey-scale closing and the input. @@ -1165,7 +1153,7 @@ transforms for three different distance metrics: Euclidean, City Block, and Chessboard distances. - The function :obj:`distance_transform_cdt` uses a chamfer type + The function :func:`distance_transform_cdt` uses a chamfer type algorithm to calculate the distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest distance to the background (all non-object @@ -1187,7 +1175,7 @@ The *distances* and *indices* arguments can be used to give optional output arrays that must be of the correct size and type - (both {Int32}). + (both :ctype:`Int32`). The basics of the algorithm used to implement this function is described in: G. Borgefors, "Distance transformations in arbitrary @@ -1195,7 +1183,7 @@ 27:321-345, 1984. - The function :obj:`distance_transform_edt` calculates the exact + The function :func:`distance_transform_edt` calculates the exact euclidean distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest euclidean distance to the background (all non-object elements). @@ -1214,7 +1202,7 @@ The *distances* and *indices* arguments can be used to give optional output arrays that must be of the correct size and type - ({Float64} and {Int32}). + (:ctype:`Float64` and :ctype:`Int32`). The algorithm used to implement this function is described in: C. R. Maurer, Jr., R. Qi, and V. Raghavan, "A linear time algorithm @@ -1222,7 +1210,7 @@ in arbitrary dimensions. IEEE Trans. PAMI 25, 265-270, 2003. - The function :obj:`distance_transform_bf` uses a brute-force algorithm + The function :func:`distance_transform_bf` uses a brute-force algorithm to calculate the distance transform of the input, by replacing each object element (defined by values larger than zero) with the shortest distance to the background (all non-object elements). The @@ -1244,13 +1232,9 @@ The *distances* and *indices* arguments can be used to give optional output arrays that must be of the correct size and type - ({Float64} and {Int32}). + (:ctype:`Float64` and :ctype:`Int32`). - {This function uses a slow brute-force algorithm, the function - :func:`distance_transform_cdt` can be used to more efficiently - calculate cityblock and chessboard distance transforms. The function - :func:`distance_transform_edt` can be used to more efficiently - calculate the exact euclidean distance transform.} + .. note:: This function uses a slow brute-force algorithm, the function :func:`distance_transform_cdt` can be used to more efficiently calculate cityblock and chessboard distance transforms. The function :func:`distance_transform_edt` can be used to more efficiently calculate the exact euclidean distance transform. Segmentation and labeling @@ -1273,10 +1257,10 @@ [0 0 0 0 1 0]] The result is a binary image, in which the individual objects still -need to be identified and labeled. The function :obj:`label` generates +need to be identified and labeled. The function :func:`label` generates an array where each object is assigned a unique number: - The :obj:`label` function generates an array where the objects in the + The :func:`label` function generates an array where the objects in the input are labeled with an integer index. It returns a tuple consisting of the array of object labels and the number of objects found, unless the *output* parameter is given, in which case only @@ -1310,7 +1294,8 @@ [0 0 0 0 1 0]] If no structuring element is provided, one is generated by calling - *generate_binary_structure* (see section :ref:`ndimage-binary-morphology`) + :func:`generate_binary_structure` (see + :ref:`ndimage-binary-morphology`) using a connectivity of one (which in 2D is the 4-connected structure of the first example). The input can be of any type, any value not equal to zero is taken to be part of an object. This is @@ -1329,20 +1314,19 @@ >>> print label(l)[0] [1 0 0 0 2] - {The structuring element used by :func:`label` is assumed to be - symmetric.} + .. note:: The structuring element used by :func:`label` is assumed to be symmetric. There is a large number of other approaches for segmentation, for instance from an estimation of the borders of the objects that can be obtained for instance by derivative filters. One such an -approach is watershed segmentation. The function :obj:`watershed_ift` +approach is watershed segmentation. The function :func:`watershed_ift` generates an array where each object is assigned a unique label, from an array that localizes the object borders, generated for instance by a gradient magnitude filter. It uses an array containing initial markers for the objects: - The :obj:`watershed_ift` function applies a watershed from markers + The :func:`watershed_ift` function applies a watershed from markers algorithm, using an Iterative Forest Transform, as described in: P. Felkel, R. Wegenkittl, and M. Bruckschwaiger, "Implementation and Complexity of the Watershed-from-Markers Algorithm Computed as a @@ -1428,7 +1412,7 @@ The connectivity of the objects is defined by a structuring element. If no structuring element is provided, one is generated by - calling :func:`generate_binary_structure` (see section + calling :func:`generate_binary_structure` (see :ref:`ndimage-binary-morphology`) using a connectivity of one (which in 2D is a 4-connected structure.) For example, using an 8-connected structure with the last example yields a different object: @@ -1445,8 +1429,7 @@ [-1 2 2 2 2 2 -1] [-1 -1 -1 -1 -1 -1 -1]] - {The implementation of :func:`watershed_ift` limits the data types - of the input to \\constant{UInt8} and \\constant{UInt16}.} + .. note:: The implementation of :func:`watershed_ift` limits the data types of the input to :ctype:`UInt8` and :ctype:`UInt16`. .. _ndimage-object-measurements: @@ -1457,11 +1440,11 @@ .. currentmodule:: scipy.ndimage.measurements Given an array of labeled objects, the properties of the individual -objects can be measured. The :obj:`find_objects` function can be used +objects can be measured. The :func:`find_objects` function can be used to generate a list of slices that for each object, give the smallest sub-array that fully contains the object: - The :obj:`find_objects` function finds all objects in a labeled array and + The :func:`find_objects` function finds all objects in a labeled array and returns a list of slices that correspond to the smallest regions in the array that contains the object. For instance: @@ -1551,28 +1534,28 @@ one result, return their result as a tuple if *index* is a single number, or as a tuple of lists, if *index* is a sequence. - The :obj:`sum` function calculates the sum of the elements of the object + The :func:`sum` function calculates the sum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :obj:`mean` function calculates the mean of the elements of the + The :func:`mean` function calculates the mean of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :obj:`variance` function calculates the variance of the elements of + The :func:`variance` function calculates the variance of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :obj:`standard_deviation` function calculates the standard + The :func:`standard_deviation` function calculates the standard deviation of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as @@ -1580,21 +1563,21 @@ used in the calculation. - The :obj:`minimum` function calculates the minimum of the elements of + The :func:`minimum` function calculates the minimum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :obj:`maximum` function calculates the maximum of the elements of + The :func:`maximum` function calculates the maximum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. - The :obj:`minimum_position` function calculates the position of the + The :func:`minimum_position` function calculates the position of the minimum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as @@ -1602,7 +1585,7 @@ used in the calculation. - The :obj:`maximum_position` function calculates the position of the + The :func:`maximum_position` function calculates the position of the maximum of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as @@ -1610,7 +1593,7 @@ used in the calculation. - The :obj:`extrema` function calculates the minimum, the maximum, and + The :func:`extrema` function calculates the minimum, the maximum, and their positions, of the elements of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are @@ -1623,7 +1606,7 @@ above. - The :obj:`center_of_mass` function calculates the center of mass of + The :func:`center_of_mass` function calculates the center of mass of the of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single @@ -1631,14 +1614,14 @@ the calculation. - The :obj:`histogram` function calculates a histogram of the of the + The :func:`histogram` function calculates a histogram of the of the object with label(s) given by *index*, using the *labels* array for the object labels. If *index* is None, all elements with a non-zero label value are treated as a single object. If *label* is None, all elements of *input* are used in the calculation. Histograms are defined by their minimum (*min*), maximum (*max*) and the number of bins (*bins*). They are returned as - one-dimensional arrays of type Int32. + one-dimensional arrays of type :ctype:`Int32`. .. _ndimage-ccallbacks: @@ -1646,11 +1629,15 @@ Extending :mod:`ndimage` in C ----------------------------- -A few functions in the :mod:`scipy.ndimage` take a call-back argument. This can be a python function, but also a CObject containing a pointer to a C function. To use this feature, you must write your own C extension that defines the function, and define a python function that -returns a CObject containing a pointer to this function. +.. highlight:: c +A few functions in the :mod:`scipy.ndimage` take a call-back +argument. This can be a python function, but also a :ctype:`PyCObject` +containing a pointer to a C function. To use this feature, you must +write your own C extension that defines the function, and define a Python function that returns a :ctype:`PyCObject` containing a pointer to this function. + An example of a function that supports this is -:func:`geometric_transform` (see section :ref:`ndimage-interpolation`). +:func:`geometric_transform` (see :ref:`ndimage-interpolation`). You can pass it a python callable object that defines a mapping from all output coordinates to corresponding coordinates in the input array. This mapping function can also be a C function, which @@ -1688,7 +1675,7 @@ A pointer to this function and a pointer to the shift value must be passed to :func:`geometric_transform`. Both are passed by a single -CObject which is created by the following python extension +:ctype:`PyCObject` which is created by the following python extension function: :: @@ -1712,10 +1699,10 @@ The value of the shift is obtained and then assigned to a dynamically allocated memory location. Both this data pointer and -the function pointer are then wrapped in a CObject, which is +the function pointer are then wrapped in a :ctype:`PyCObject`, which is returned. Additionally, a pointer to a destructor function is given, that will free the memory we allocated for the shift value -when the CObject is destroyed. This destructor is very simple: +when the :ctype:`PyCObject` is destroyed. This destructor is very simple: :: @@ -1726,7 +1713,7 @@ free(cdata); } -To use these functions, an extension module is build: +To use these functions, an extension module is built: :: @@ -1743,6 +1730,8 @@ This extension can then be used in Python, for example: +.. highlight:: python + :: >>> import example @@ -1754,7 +1743,7 @@ [ 0. 4.8125 6.1875] [ 0. 8.2625 9.6375]] -C Callback functions for use with :mod:`ndimage` functions must all +C callback functions for use with :mod:`ndimage` functions must all be written according to this scheme. The next section lists the :mod:`ndimage` functions that acccept a C callback function and gives the prototype of the callback function. @@ -1767,18 +1756,18 @@ provided to these functions must match exactly that what they expect. Therefore we give here the prototypes of the callback functions. All these callback functions accept a void -*callback_data* pointer that must be wrapped in a CObject using -the Python {PyCObject_FromVoidPtrAndDesc} function, which can also +*callback_data* pointer that must be wrapped in a :ctype:`PyCObject` using +the Python :cfunc:`PyCObject_FromVoidPtrAndDesc` function, which can also accept a pointer to a destructor function to free any memory allocated for *callback_data*. If *callback_data* is not needed, -{PyCObject_FromVoidPtr} may be used instead. The callback +:cfunc:`PyCObject_FromVoidPtr` may be used instead. The callback functions must return an integer error status that is equal to zero if something went wrong, or 1 otherwise. If an error occurs, you should normally set the python error status with an informative message before returning, otherwise, a default error message is set by the calling function. -The function :func:`generic_filter` (see section +The function :func:`generic_filter` (see :ref:`ndimage-genericfilters`) accepts a callback function with the following prototype: @@ -1790,7 +1779,7 @@ calculated valued should be returned in the *return_value* argument. -The function :func:`generic_filter1d` (see section +The function :func:`generic_filter1d` (see :ref:`ndimage-genericfilters`) accepts a callback function with the following prototype: @@ -1804,7 +1793,7 @@ in the array passed through *output_line*. The length of the output line is passed through *output_length*. -The function :func:`geometric_transform` (see section +The function :func:`geometric_transform` (see :ref:`ndimage-interpolation`) expects a function with the following prototype: From scipy-svn at scipy.org Sun Dec 21 12:33:43 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 21 Dec 2008 11:33:43 -0600 (CST) Subject: [Scipy-svn] r5285 - in trunk/scipy/stats: . tests Message-ID: <20081221173343.F0E27C7C07B@scipy.org> Author: josef Date: 2008-12-21 11:33:40 -0600 (Sun, 21 Dec 2008) New Revision: 5285 Modified: trunk/scipy/stats/stats.py trunk/scipy/stats/tests/test_stats.py Log: cleaning up stats.ttests, add tests, tests and doctests pass, see http://projects.scipy.org/pipermail/scipy-dev/2008-December/010670.html Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-20 13:50:20 UTC (rev 5284) +++ trunk/scipy/stats/stats.py 2008-12-21 17:33:40 UTC (rev 5285) @@ -1870,23 +1870,33 @@ ##### INFERENTIAL STATISTICS ##### ##################################### -def ttest_1samp(a, popmean): +def ttest_1samp(a, popmean, axis=0): """ Calculates the t-obtained for the independent samples T-test on ONE group of scores a, given a population mean. Returns: t-value, two-tailed prob """ - a = asarray(a) - x = np.mean(a) - v = np.var(a, ddof=1) - n = len(a) - df = n-1 - svar = ((n-1)*v) / float(df) - t = (x-popmean)/np.sqrt(svar*(1.0/n)) - #prob = betai(0.5*df,0.5,df/(df+t*t)) + + + a, axis = _chk_asarray(a, axis) + n = a.shape[axis] + df=n-1 + + d = np.mean(a,axis) - popmean + v = np.var(a, axis, ddof=1) + + t = d / np.sqrt(v/float(n)) + t = np.where((d==0)*(v==0), 1.0, t) #define t=0/0 = 1, identical mean, var prob = distributions.t.sf(np.abs(t),df)*2 #use np.abs to get upper tail + #distributions.t.sf currently does not propagate nans + #this can be dropped, if distributions.t.sf propagates nans + #if this is removed, then prob = prob[()] needs to be removed + prob = np.where(np.isnan(t), np.nan, prob) + if t.ndim == 0: + t = t[()] + prob = prob[()] return t,prob @@ -1928,38 +1938,44 @@ # test with sample with identical means >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) - >>> stats.ttest_ind(rvs1,rvs2) - (array(0.26833823296239279), 0.78849443369564765) + >>> ttest_ind(rvs1,rvs2) + (0.26833823296239279, 0.78849443369564765) # test with sample with different means >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) - >>> stats.ttest_ind(rvs1,rvs3) - (array(-5.0434013458585092), 5.4302979468623391e-007) + >>> ttest_ind(rvs1,rvs3) + (-5.0434013458585092, 5.4302979468623391e-007) """ a, b, axis = _chk2_asarray(a, b, axis) - x1 = mean(a,axis) - x2 = mean(b,axis) - v1 = var(a,axis) - v2 = var(b,axis) + + v1 = np.var(a,axis,ddof = 1) + v2 = np.var(b,axis,ddof = 1) n1 = a.shape[axis] n2 = b.shape[axis] df = n1+n2-2 + + d = mean(a,axis) - mean(b,axis) svar = ((n1-1)*v1+(n2-1)*v2) / float(df) - zerodivproblem = svar == 0 - t = (x1-x2)/np.sqrt(svar*(1.0/n1 + 1.0/n2)) # N-D COMPUTATION HERE!!!!!! - t = np.where(zerodivproblem, 1.0, t) # replace NaN t-values with 1.0 - probs = distributions.t.sf(np.abs(t),df)*2 - if not np.isscalar(t): - probs = probs.reshape(t.shape) - if not np.isscalar(probs) and len(probs) == 1: - probs = probs[0] - return t, probs + t = d/np.sqrt(svar*(1.0/n1 + 1.0/n2)) + t = np.where((d==0)*(svar==0), 1.0, t) #define t=0/0 = 0, identical means + prob = distributions.t.sf(np.abs(t),df)*2#use np.abs to get upper tail + + #distributions.t.sf currently does not propagate nans + #this can be dropped, if distributions.t.sf propagates nans + #if this is removed, then prob = prob[()] needs to be removed + prob = np.where(np.isnan(t), np.nan, prob) + if t.ndim == 0: + t = t[()] + prob = prob[()] + + return t, prob -def ttest_rel(a,b,axis=None): + +def ttest_rel(a,b,axis=0): """Calculates the t-obtained T-test on TWO RELATED samples of scores, a and b. From Numerical Recipies, p.483. Axis can equal None (ravel array first), or an integer (the axis over which to operate on a and b). @@ -1987,8 +2003,6 @@ Examples -------- - (note: after changes difference in 13th decimal) - >>> from scipy import stats >>> import numpy as np @@ -1998,35 +2012,40 @@ >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) + \ stats.norm.rvs(scale=0.2,size=500) >>> stats.ttest_rel(rvs1,rvs2) - (array(0.24101764965300965), 0.80964043445811562) + (0.24101764965300962, 0.80964043445811562) >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) + \ stats.norm.rvs(scale=0.2,size=500) >>> stats.ttest_rel(rvs1,rvs3) - (array(-3.9995108708727929), 7.3082402191726459e-005) + (-3.9995108708727933, 7.3082402191726459e-005) """ a, b, axis = _chk2_asarray(a, b, axis) - if len(a)!=len(b): + if a.shape[axis] != b.shape[axis]: raise ValueError, 'unequal length arrays' - x1 = mean(a,axis) - x2 = mean(b,axis) - v1 = var(a,axis) - v2 = var(b,axis) n = a.shape[axis] df = float(n-1) + d = (a-b).astype('d') + v = np.var(d,axis,ddof=1) + dm = np.mean(d, axis) + + t = dm / np.sqrt(v/float(n)) + t = np.where((dm==0)*(v==0), 1.0, t) #define t=0/0 = 1, zero mean and var + prob = distributions.t.sf(np.abs(t),df)*2 #use np.abs to get upper tail + #distributions.t.sf currently does not propagate nans + #this can be dropped, if distributions.t.sf propagates nans + #if this is removed, then prob = prob[()] needs to be removed + prob = np.where(np.isnan(t), np.nan, prob) + +## if not np.isscalar(t): +## probs = np.reshape(probs, t.shape) # this should be redundant +## if not np.isscalar(prob) and len(prob) == 1: +## prob = prob[0] + if t.ndim == 0: + t = t[()] + prob = prob[()] - #denom is just sqrt(var(d)/df) - denom = np.sqrt(np.var(d,axis,ddof=1)/float(n)) - zerodivproblem = denom == 0 - t = np.mean(d, axis) / denom - t = np.where(zerodivproblem, 1.0, t) # replace NaN t-values with 1.0 - probs = distributions.t.sf(np.abs(t),df)*2 - if not np.isscalar(t): - probs = np.reshape(probs, t.shape) - if not np.isscalar(probs) and len(probs) == 1: - probs = probs[0] - return t, probs + return t, prob #import scipy.stats Modified: trunk/scipy/stats/tests/test_stats.py =================================================================== --- trunk/scipy/stats/tests/test_stats.py 2008-12-20 13:50:20 UTC (rev 5284) +++ trunk/scipy/stats/tests/test_stats.py 2008-12-21 17:33:40 UTC (rev 5285) @@ -1071,7 +1071,110 @@ t,p = stats.ttest_rel(rvs1_2D, rvs2_2D, axis=1) assert_array_almost_equal([t,p],tpr) + #test on 3 dimensions + rvs1_3D = np.dstack([rvs1_2D,rvs1_2D,rvs1_2D]) + rvs2_3D = np.dstack([rvs2_2D,rvs2_2D,rvs2_2D]) + t,p = stats.ttest_rel(rvs1_3D, rvs2_3D, axis=1) + assert_array_almost_equal(np.abs(t), tr) + assert_array_almost_equal(np.abs(p), pr) + assert_equal(t.shape, (2, 3)) + t,p = stats.ttest_rel(np.rollaxis(rvs1_3D,2), np.rollaxis(rvs2_3D,2), axis=2) + assert_array_almost_equal(np.abs(t), tr) + assert_array_almost_equal(np.abs(p), pr) + assert_equal(t.shape, (3, 2)) + #test zero division problem + t,p = stats.ttest_rel([0,0,0],[1,1,1]) + assert_equal((np.abs(t),p), (np.inf, 0)) + assert_equal(stats.ttest_rel([0,0,0], [0,0,0]), (1.0, 0.42264973081037427)) + + #check that nan in input array result in nan output + anan = np.array([[1,np.nan],[-1,1]]) + assert_equal(stats.ttest_ind(anan, np.zeros((2,2))),([0, np.nan], [1,np.nan])) + + +def test_ttest_ind(): + #regression test + tr = 1.0912746897927283 + pr = 0.27647818616351882 + tpr = ([tr,-tr],[pr,pr]) + + rvs2 = np.linspace(1,100,100) + rvs1 = np.linspace(5,105,100) + rvs1_2D = np.array([rvs1, rvs2]) + rvs2_2D = np.array([rvs2, rvs1]) + + t,p = stats.ttest_ind(rvs1, rvs2, axis=0) + assert_array_almost_equal([t,p],(tr,pr)) + t,p = stats.ttest_ind(rvs1_2D.T, rvs2_2D.T, axis=0) + assert_array_almost_equal([t,p],tpr) + t,p = stats.ttest_ind(rvs1_2D, rvs2_2D, axis=1) + assert_array_almost_equal([t,p],tpr) + + #test on 3 dimensions + rvs1_3D = np.dstack([rvs1_2D,rvs1_2D,rvs1_2D]) + rvs2_3D = np.dstack([rvs2_2D,rvs2_2D,rvs2_2D]) + t,p = stats.ttest_ind(rvs1_3D, rvs2_3D, axis=1) + assert_almost_equal(np.abs(t), np.abs(tr)) + assert_array_almost_equal(np.abs(p), pr) + assert_equal(t.shape, (2, 3)) + + t,p = stats.ttest_ind(np.rollaxis(rvs1_3D,2), np.rollaxis(rvs2_3D,2), axis=2) + assert_array_almost_equal(np.abs(t), np.abs(tr)) + assert_array_almost_equal(np.abs(p), pr) + assert_equal(t.shape, (3, 2)) + + #test zero division problem + t,p = stats.ttest_ind([0,0,0],[1,1,1]) + assert_equal((np.abs(t),p), (np.inf, 0)) + assert_equal(stats.ttest_ind([0,0,0], [0,0,0]), (1.0, 0.37390096630005898)) + + #check that nan in input array result in nan output + anan = np.array([[1,np.nan],[-1,1]]) + assert_equal(stats.ttest_ind(anan, np.zeros((2,2))),([0, np.nan], [1,np.nan])) + + + + +def test_ttest_1samp_new(): + n1, n2, n3 = (10,15,20) + rvn1 = stats.norm.rvs(loc=5,scale=10,size=(n1,n2,n3)) + rvn2 = stats.norm.rvs(loc=5,scale=10,size=(n1,n2,n3)) + + #check multidimensional array and correct axis handling + #deterministic rvn1 and rvn2 would be better as in test_ttest_rel + t1,p1 = stats.ttest_1samp(rvn1[:,:,:], np.ones((n2,n3)),axis=0) + t2,p2 = stats.ttest_1samp(rvn1[:,:,:], 1,axis=0) + t3,p3 = stats.ttest_1samp(rvn1[:,0,0], 1) + assert_array_almost_equal(t1,t2, decimal=14) + assert_almost_equal(t1[0,0],t3, decimal=14) + assert_equal(t1.shape, (n2,n3)) + + t1,p1 = stats.ttest_1samp(rvn1[:,:,:], np.ones((n1,n3)),axis=1) + t2,p2 = stats.ttest_1samp(rvn1[:,:,:], 1,axis=1) + t3,p3 = stats.ttest_1samp(rvn1[0,:,0], 1) + assert_array_almost_equal(t1,t2, decimal=14) + assert_almost_equal(t1[0,0],t3, decimal=14) + assert_equal(t1.shape, (n1,n3)) + + t1,p1 = stats.ttest_1samp(rvn1[:,:,:], np.ones((n1,n2)),axis=2) + t2,p2 = stats.ttest_1samp(rvn1[:,:,:], 1,axis=2) + t3,p3 = stats.ttest_1samp(rvn1[0,0,:], 1) + assert_array_almost_equal(t1,t2, decimal=14) + assert_almost_equal(t1[0,0],t3, decimal=14) + assert_equal(t1.shape, (n1,n2)) + + #test zero division problem + t,p = stats.ttest_1samp([0,0,0], 1) + assert_equal((np.abs(t),p), (np.inf, 0)) + assert_equal(stats.ttest_1samp([0,0,0], 0), (1.0, 0.42264973081037427)) + + #check that nan in input array result in nan output + anan = np.array([[1,np.nan],[-1,1]]) + assert_equal(stats.ttest_1samp(anan, 0),([0, np.nan], [1,np.nan])) + + + if __name__ == "__main__": run_module_suite() From scipy-svn at scipy.org Sun Dec 21 17:23:35 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sun, 21 Dec 2008 16:23:35 -0600 (CST) Subject: [Scipy-svn] r5286 - trunk/doc/source Message-ID: <20081221222335.37013C7C062@scipy.org> Author: josef Date: 2008-12-21 16:23:31 -0600 (Sun, 21 Dec 2008) New Revision: 5286 Added: trunk/doc/source/stats.mstats.rst Log: add function list for stats.mstats; list was autogenerated and not yet sorted or screened for unimportant functions Added: trunk/doc/source/stats.mstats.rst =================================================================== --- trunk/doc/source/stats.mstats.rst 2008-12-21 17:33:40 UTC (rev 5285) +++ trunk/doc/source/stats.mstats.rst 2008-12-21 22:23:31 UTC (rev 5286) @@ -0,0 +1,82 @@ +.. module:: scipy.stats.mstats + +=================================================================== +Statistical functions for masked arrays (:mod:`scipy.stats.mstats`) +=================================================================== + +This module contains a large number of statistical functions that can +be used with masked arrays. + +Most of these functions are similar to those in scipy.stats but might +have small differences in the API or in the algorithm used. Since this +is a relatively new package, some API changes are still possible. + +.. autosummary:: + :toctree: generated/ + + +argstoarray +betai +chisquare +count_tied_groups +describe +f_oneway +f_value_wilks_lambda +find_repeats +friedmanchisquare +gmean +hmean +kendalltau +kendalltau_seasonal +kruskalwallis +kruskalwallis +ks_twosamp +ks_twosamp +kurtosis +kurtosistest +linregress +mannwhitneyu +plotting_positions +mode +moment +mquantiles +msign +normaltest +obrientransform +pearsonr +plotting_positions +pointbiserialr +rankdata +samplestd +samplevar +scoreatpercentile +sem +signaltonoise +skew +skewtest +spearmanr +std +stderr +theilslopes +threshold +tmax +tmean +tmin +trim +trima +trimboth +trimmed_stde +trimr +trimtail +tsem +ttest_onesamp +ttest_ind +ttest_onesamp +ttest_rel +tvar +var +variation +winsorize +z +zmap +zs From scipy-svn at scipy.org Wed Dec 24 16:40:14 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 24 Dec 2008 15:40:14 -0600 (CST) Subject: [Scipy-svn] r5287 - trunk/scipy/stats Message-ID: <20081224214014.ECE5DC7C00B@scipy.org> Author: josef Date: 2008-12-24 15:40:10 -0600 (Wed, 24 Dec 2008) New Revision: 5287 Modified: trunk/scipy/stats/morestats.py Log: remove broken usage of xplt, make usage of matplotlib possible. no tests added, visual inspection Modified: trunk/scipy/stats/morestats.py =================================================================== --- trunk/scipy/stats/morestats.py 2008-12-21 22:23:31 UTC (rev 5286) +++ trunk/scipy/stats/morestats.py 2008-12-24 21:40:10 UTC (rev 5287) @@ -251,21 +251,16 @@ # perform a linear fit. slope, intercept, r, prob, sterrest = stats.linregress(osm,osr) if plot is not None: - try: - import scipy.xplt as xplt - xplt.limits() - except: pass plot.plot(osm, osr, 'o', osm, slope*osm + intercept) plot.title('Probability Plot') plot.xlabel('Order Statistic Medians') plot.ylabel('Ordered Values') - try: plot.expand_limits(5) - except: pass + xmin,xmax= amin(osm),amax(osm) ymin,ymax= amin(x),amax(x) - pos = xmin+0.70*(xmax-xmin), ymin+0.01*(ymax-ymin) - try: plot.addtext("r^2^=%1.4f" % r, xy=pos,tosys=1) - except: pass + posx,posy = xmin+0.70*(xmax-xmin), ymin+0.01*(ymax-ymin) + #plot.addtext("r^2^=%1.4f" % r, xy=pos,tosys=1) + plot.text(posx,posy, "r^2=%1.4f" % r) if fit: return (osm, osr), (slope, intercept, r) else: @@ -326,16 +321,10 @@ ppcc[k] = r2[-1] k += 1 if plot is not None: - try: - import scipy.xplt as xplt - xplt.limits() - except: pass plot.plot(svals, ppcc, 'x') plot.title('(%s) PPCC Plot' % dist) - plot.xlabel('Prob Plot Corr. Coef.',deltay=-0.01) - plot.ylabel('Shape Values',deltax=-0.01) - try: plot.expand_limits(5) - except: pass + plot.xlabel('Prob Plot Corr. Coef.')#,deltay=-0.01) + plot.ylabel('Shape Values')#,deltax=-0.01) return svals, ppcc def boxcox_llf(lmb, data): @@ -395,7 +384,7 @@ def tempfunc(lmb, data): # function to minimize return -boxcox_llf(lmb,data) lmax = optimize.brent(tempfunc, brack=(-2.0,2.0),args=(x,)) - y, lmax = boxcox(x, lmax) + y = boxcox(x, lmax) if alpha is None: return y, lmax # Otherwise find confidence interval @@ -429,20 +418,16 @@ ppcc = svals*0.0 k = 0 for sval in svals: - r1,r2 = probplot(x,dist='norm',fit=1) + #JP: this doesn't use sval, creates constant ppcc, and horizontal line + z = boxcox(x,sval) #JP: this was missing + r1,r2 = probplot(z,dist='norm',fit=1) ppcc[k] = r2[-1] k +=1 if plot is not None: - try: - import scipy.xplt as xplt - xplt.limits() - except: pass plot.plot(svals, ppcc, 'x') plot.title('Box-Cox Normality Plot') - plot.xlabel('Prob Plot Corr. Coef.',deltay=-0.01) - plot.ylabel('Transformation parameter',deltax=-0.01) - try: plot.expand_limits(5) - except: pass + plot.xlabel('Prob Plot Corr. Coef.') + plot.ylabel('Transformation parameter') return svals, ppcc def shapiro(x,a=None,reta=0): @@ -957,7 +942,9 @@ def wilcoxon(x,y=None): """ -Calculates the Wilcoxon signed-rank test for the null hypothesis that two samples come from the same distribution. A non-parametric T-test. (need N > 20) +Calculates the Wilcoxon signed-rank test for the null hypothesis that two +samples come from the same distribution. A non-parametric T-test. +(need N > 20) Returns: t-statistic, two-tailed p-value """ From scipy-svn at scipy.org Wed Dec 24 16:44:55 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 24 Dec 2008 15:44:55 -0600 (CST) Subject: [Scipy-svn] r5288 - trunk/scipy/stats Message-ID: <20081224214455.5F9B7C7C00B@scipy.org> Author: josef Date: 2008-12-24 15:44:53 -0600 (Wed, 24 Dec 2008) New Revision: 5288 Modified: trunk/scipy/stats/stats.py Log: kurtosistest: return number instead of 0-dim array Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-24 21:40:10 UTC (rev 5287) +++ trunk/scipy/stats/stats.py 2008-12-24 21:44:53 UTC (rev 5288) @@ -925,6 +925,9 @@ term2 = np.where(denom < 0, term1, np.power((1-2.0/A)/denom,1/3.0)) Z = ( term1 - term2 ) / np.sqrt(2/(9.0*A)) Z = np.where(denom == 99, 0, Z) + if Z.ndim == 0: + Z = Z[()] + #JPNote: p-value sometimes larger than 1 return Z, (1.0-zprob(Z))*2 From scipy-svn at scipy.org Fri Dec 26 17:03:46 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Fri, 26 Dec 2008 16:03:46 -0600 (CST) Subject: [Scipy-svn] r5289 - trunk/scipy/stats Message-ID: <20081226220346.D4C5BC7C027@scipy.org> Author: josef Date: 2008-12-26 16:03:43 -0600 (Fri, 26 Dec 2008) New Revision: 5289 Modified: trunk/scipy/stats/stats.py Log: cleanup docstrings of t-tests and ks-tests Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-24 21:44:53 UTC (rev 5288) +++ trunk/scipy/stats/stats.py 2008-12-26 22:03:43 UTC (rev 5289) @@ -1874,11 +1874,29 @@ ##################################### def ttest_1samp(a, popmean, axis=0): - """ -Calculates the t-obtained for the independent samples T-test on ONE group -of scores a, given a population mean. + """Calculates the T-test for the mean of ONE group of scores `a`. -Returns: t-value, two-tailed prob + This is a two-sided test for the null hypothesis that the expected value + (mean) of a sample of independent observations is equal to the given + population mean, `popmean`. + + Parameters + ---------- + a : array_like + sample observation + popmean : float or array_like + expected value in null hypothesis, if array_like than it must have the + same shape as `a` excluding the axis dimension + axis : int, optional, (default axis=0) + Axis can equal None (ravel array first), or an integer (the axis + over which to operate on a). + + Returns + ------- + t : float or array + t-statistic + prob : float or array + two-tailed p-value """ @@ -1904,31 +1922,46 @@ def ttest_ind(a, b, axis=0): - """Calculates the t-obtained T-test on TWO INDEPENDENT samples of scores - a, and b. From Numerical Recipies, p.483. Axis can equal None (ravel - array first), or an integer (the axis over which to operate on a and b). + """Calculates the T-test for the means of TWO INDEPENDENT samples of scores. - Returns: t-value, two-tailed p-value - This is a two-sided test for the null hypothesis that 2 independent samples have identical average (expected) values. - Description - ----------- + Parameters + ---------- + a, b : sequence of ndarrays + The arrays must have the same shape, except in the dimension + corresponding to `axis` (the first, by default). + axis : int, optional + Axis can equal None (ravel array first), or an integer (the axis + over which to operate on a and b). + Returns + ------- + t : float or array + t-statistic + prob : float or array + two-tailed p-value + + + Notes + ----- + We can use this test, if we observe two independent samples from the same or different population, e.g. exam scores of boys and girls or of two ethnic groups. The test measures whether the average (expected) value differs significantly across samples. If - we observe a larger p-value, for example >0.5 or 0.1 then we - cannot reject the null hypothesis of identical average scores. If - the test statistic is larger (in absolute terms than critical - value or, equivalently, if the p-value is smaller than the - threshold, 1%,5% or 10%, then we reject the null hypothesis equal - averages. + we observe a large p-value, for example larger than 0.05 or 0.1, + then we cannot reject the null hypothesis of identical average scores. + If the p-value is smaller than the threshold, e.g. 1%, 5% or 10%, + then we reject the null hypothesis of equal averages. - see: http://en.wikipedia.org/wiki/T-test#Independent_two-sample_t-test + References + ---------- + http://en.wikipedia.org/wiki/T-test#Independent_two-sample_t-test + + Examples -------- @@ -1941,13 +1974,13 @@ # test with sample with identical means >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) - >>> ttest_ind(rvs1,rvs2) + >>> stats.ttest_ind(rvs1,rvs2) (0.26833823296239279, 0.78849443369564765) # test with sample with different means >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) - >>> ttest_ind(rvs1,rvs3) + >>> stats.ttest_ind(rvs1,rvs3) (-5.0434013458585092, 5.4302979468623391e-007) """ @@ -1979,30 +2012,45 @@ def ttest_rel(a,b,axis=0): - """Calculates the t-obtained T-test on TWO RELATED samples of scores, a - and b. From Numerical Recipies, p.483. Axis can equal None (ravel array - first), or an integer (the axis over which to operate on a and b). + """Calculates the T-test on TWO RELATED samples of scores, a and b. - Returns: t-value, two-tailed p-value + This is a two-sided test for the null hypothesis that 2 related or + repeated samples have identical average (expected) values. - Description - ----------- + Parameters + ---------- + a, b : sequence of ndarrays + The arrays must have the same shape. + axis : int, optional, (default axis=0) + Axis can equal None (ravel array first), or an integer (the axis + over which to operate on a and b). - This is a two-sided test for the null hypothesis that 2 repeated samples - have identical average values. + Returns + ------- + t : float or array + t-statistic + prob : float or array + two-tailed p-value - Examples for the use are scores of a student in different exams, - or repeated sampling from the same units. The test measures - whether the average score differs significantly across samples - (e.g. exams). If we observe a larger p-value, for example >0.5 or - 0.1 then we cannot reject the null hypothesis of identical average - scores. If the test statistic is larger (in absolute terms than - critical value or, equivalently, if the p-value is smaller than - the threshold, 1%,5% or 10%, then we reject the null hypothesis - equal averages. - see: http://en.wikipedia.org/wiki/T-test#Dependent_t-test + Notes + ----- + Examples for the use are scores of the same set of student in + different exams, or repeated sampling from the same units. The + test measures whether the average score differs significantly + across samples (e.g. exams). If we observe a large p-value, for + example greater than 0.5 or 0.1 then we cannot reject the null + hypothesis of identical average scores. If the p-value is smaller + than the threshold, e.g. 1%, 5% or 10%, then we reject the null + hypothesis of equal averages. Small p-values are associated with + large t-statistics. + + References + ---------- + + http://en.wikipedia.org/wiki/T-test#Dependent_t-test + Examples -------- @@ -2056,24 +2104,17 @@ def kstest(rvs, cdf, args=(), N=20, alternative = 'two_sided', mode='approx',**kwds): """Return the D-value and the p-value for a Kolmogorov-Smirnov test + This performs a test of the distribution G(x) of an observed + random variable against a given distribution F(x). Under the null + hypothesis the two distributions are identical, G(x)=F(x). The + alternative hypothesis can be either 'two_sided' (default), 'less' + or 'greater'. The KS test is only valid for continuous distributions. - This performs a test of the distribution of random variables G(x) against - a given distribution F(x). Under the null hypothesis the two distributions - are identical, G(x)=F(x). The alternative hypothesis can be either - 'two_sided' (default), 'less' or 'greater'. In the two one-sided test, - the alternative is that the empirical cumulative distribution function, - of the random variable is "less" or "greater" then the cumulative - distribution function of the hypothesis F(x), G(x)<=F(x), resp. G(x)>=F(x). - - If the p-value is greater than the significance level (say 5%), then we - cannot reject the hypothesis that the data come from the given - distribution. - Parameters ---------- rvs : string or array or callable string: name of a distribution in scipy.stats - array: random variables + array: 1-D observations of random variables callable: function to generate random variables, requires keyword argument size cdf : string or callable @@ -2082,21 +2123,37 @@ or be the same as rvs callable: function to evaluate cdf - args : distribution parameters used if rvs or cdf are strings - N : sample size if rvs is string or callable + args : tuple, sequence + distribution parameters, used if rvs or cdf are strings + N : int + sample size if rvs is string or callable alternative : 'two_sided' (default), 'less' or 'greater' defines the alternative hypothesis (see explanation) mode : 'approx' (default) or 'asymp' - defines distribution used for calculating p-value + defines the distribution used for calculating p-value 'approx' : use approximation to exact distribution of test statistic 'asymp' : use asymptotic distribution of test statistic Returns ------- - D: test statistic either D, D+ or D- - p-value + D : float + KS test statistic, either D, D+ or D- + p-value : float + one-tailed or two-tailed p-value + Notes + ----- + + In the two one-sided test, the alternative is that the empirical + cumulative distribution function of the random variable is "less" + or "greater" then the cumulative distribution function F(x) of the + hypothesis, G(x)<=F(x), resp. G(x)>=F(x). + + If the p-value is greater than the significance level (say 5%), then we + cannot reject the hypothesis that the data come from the given + distribution. + Examples -------- @@ -2214,25 +2271,37 @@ def ks_2samp(data1, data2): """ Computes the Kolmogorov-Smirnof statistic on 2 samples. - data1, data2: array_like, 1-dim - samples assumed to be drawn from a continuous distribution, - sample sizes can be different + This is a two-sided test for the null hypothesis that 2 independent samples + are drawn from the same continuous distribution. - Returns: KS D-value, p-value + Parameters + ---------- + a, b : sequence of 1-D ndarrays + two arrays of sample observations assumed to be drawn from a continuous + distribution, sample sizes can be different - Description: - ------------ - Tests whether 2 samples are drawn from the same distribution. Note - that, like the one-sample K-S test the distribution is assumed to be - continuous. + Returns + ------- + D : float + KS statistic + p-value : float + two-tailed p-value + + Notes + ----- + + This tests whether 2 samples are drawn from the same distribution. Note + that, like in the case of the one-sample K-S test, the distribution is + assumed to be continuous. + This is the two-sided test, one-sided tests are not implemented. The test uses the two-sided asymptotic Kolmogorov-Smirnov distribution. If the K-S statistic is small or the p-value is high, then we cannot - reject the hypothesis that the two distributions of the two samples - are the same + reject the hypothesis that the distributions of the two samples + are the same. Examples: --------- From scipy-svn at scipy.org Fri Dec 26 19:46:26 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Fri, 26 Dec 2008 18:46:26 -0600 (CST) Subject: [Scipy-svn] r5290 - trunk/scipy/stats Message-ID: <20081227004626.C4464C7C027@scipy.org> Author: josef Date: 2008-12-26 18:46:24 -0600 (Fri, 26 Dec 2008) New Revision: 5290 Modified: trunk/scipy/stats/stats.py Log: docstring cleaning and add example to ttest_1samp Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-26 22:03:43 UTC (rev 5289) +++ trunk/scipy/stats/stats.py 2008-12-27 00:46:24 UTC (rev 5290) @@ -1897,6 +1897,37 @@ t-statistic prob : float or array two-tailed p-value + + Examples + -------- + + >>> from scipy import stats + >>> import numpy as np + + >>> #fix seed to get the same result + >>> np.random.seed(7654567) + >>> rvs = stats.norm.rvs(loc=5,scale=10,size=(50,2)) + + test if mean of random sample is equal to true mean, and different mean. + We reject the null hypothesis in the second case and don't reject it in + the first case + + >>> stats.ttest_1samp(rvs,5.0) + (array([-0.68014479, -0.04323899]), array([ 0.49961383, 0.96568674])) + >>> stats.ttest_1samp(rvs,0.0) + (array([ 2.77025808, 4.11038784]), array([ 0.00789095, 0.00014999])) + + examples using axis and non-scalar dimension for population mean + + >>> stats.ttest_1samp(rvs,[5.0,0.0]) + (array([-0.68014479, 4.11038784]), array([ 4.99613833e-01, 1.49986458e-04])) + >>> stats.ttest_1samp(rvs.T,[5.0,0.0],axis=1) + (array([-0.68014479, 4.11038784]), array([ 4.99613833e-01, 1.49986458e-04])) + >>> stats.ttest_1samp(rvs,[[5.0],[0.0]]) + (array([[-0.68014479, -0.04323899], + [ 2.77025808, 4.11038784]]), array([[ 4.99613833e-01, 9.65686743e-01], + [ 7.89094663e-03, 1.49986458e-04]])) + """ @@ -1968,17 +1999,19 @@ >>> from scipy import stats >>> import numpy as np - #fix seed to get the same result + >>> #fix seed to get the same result >>> np.random.seed(12345678) - # test with sample with identical means + test with sample with identical means + >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) >>> stats.ttest_ind(rvs1,rvs2) (0.26833823296239279, 0.78849443369564765) - # test with sample with different means + test with sample with different means + >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) >>> stats.ttest_ind(rvs1,rvs3) (-5.0434013458585092, 5.4302979468623391e-007) @@ -2057,7 +2090,7 @@ >>> from scipy import stats >>> import numpy as np - #fix random seed to get the same result + >>> #fix random seed to get the same result >>> np.random.seed(12345678) >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) + \ @@ -2114,13 +2147,17 @@ ---------- rvs : string or array or callable string: name of a distribution in scipy.stats + array: 1-D observations of random variables + callable: function to generate random variables, - requires keyword argument size + requires keyword argument `size` + cdf : string or callable string: name of a distribution in scipy.stats - if rvs is a string then cdf can evaluate to False - or be the same as rvs + if rvs is a string then cdf can evaluate to False + or be the same as rvs + callable: function to evaluate cdf args : tuple, sequence @@ -2131,7 +2168,9 @@ defines the alternative hypothesis (see explanation) mode : 'approx' (default) or 'asymp' defines the distribution used for calculating p-value + 'approx' : use approximation to exact distribution of test statistic + 'asymp' : use asymptotic distribution of test statistic @@ -2165,33 +2204,33 @@ >>> kstest(x,'norm') (0.44435602715924361, 0.038850142705171065) - # fix random seed to get the same result + >>> #fix random seed to get the same result >>> np.random.seed(987654321) >>> kstest('norm','',N=100) (0.058352892479417884, 0.88531190944151261) is equivalent to this + >>> np.random.seed(987654321) >>> kstest(stats.norm.rvs(size=100),'norm') (0.058352892479417884, 0.88531190944151261) - test against one-sided alternative hypothesis - --------------------------------------------- + **test against one-sided alternative hypothesis** + >>> np.random.seed(987654321) - >>> # shift distribution to larger values, so that cdf_dgp(x)< norm.cdf(x) + >>> #shift distribution to larger values, so that cdf_dgp(x)< norm.cdf(x) >>> x = stats.norm.rvs(loc=0.2, size=100) >>> kstest(x,'norm', alternative = 'less') (0.12464329735846891, 0.040989164077641749) - >>> # reject equal distribution against alternative hypothesis: less + >>> #reject equal distribution against alternative hypothesis: less >>> kstest(x,'norm', alternative = 'greater') (0.0072115233216311081, 0.98531158590396395) - >>> # don't reject equal distribution against alternative hypothesis: greater + >>> #don't reject equal distribution against alternative hypothesis: greater >>> kstest(x,'norm', mode='asymp') (0.12464329735846891, 0.08944488871182088) - testing t distributed random variables against normal distribution - ------------------------------------------------------------------ + **testing t distributed random variables against normal distribution** With 100 degrees of freedom the t distribution looks close to the normal distribution, and the kstest does not reject the hypothesis that the sample @@ -2201,7 +2240,6 @@ >>> stats.kstest(stats.t.rvs(100,size=100),'norm') (0.072018929165471257, 0.67630062862479168) - With 3 degrees of freedom the t distribution looks sufficiently different from the normal distribution, that we can reject the hypothesis that the sample came from the normal distribution at a alpha=10% level @@ -2310,14 +2348,15 @@ >>> import numpy as np >>> from scipy.stats import ks_2samp - # fix random seed to get the same result + >>> #fix random seed to get the same result >>> np.random.seed(12345678); >>> n1 = 200 # size of first sample >>> n2 = 300 # size of second sample - # different distribution + different distribution we can reject the null hypothesis since the pvalue is below 1% + >>> rvs1 = stats.norm.rvs(size=n1,loc=0.,scale=1); >>> rvs2 = stats.norm.rvs(size=n2,loc=0.5,scale=1.5) >>> ks_2samp(rvs1,rvs2) @@ -2326,12 +2365,14 @@ slightly different distribution we cannot reject the null hypothesis at a 10% or lower alpha since the pvalue at 0.144 is higher than 10% + >>> rvs3 = stats.norm.rvs(size=n2,loc=0.01,scale=1.0) >>> ks_2samp(rvs1,rvs3) (0.10333333333333333, 0.14498781825751686) identical distribution we cannot reject the null hypothesis since the pvalue is high, 41% + >>> rvs4 = stats.norm.rvs(size=n2,loc=0.0,scale=1.0) >>> ks_2samp(rvs1,rvs4) (0.07999999999999996, 0.41126949729859719) From scipy-svn at scipy.org Sat Dec 27 06:31:15 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 27 Dec 2008 05:31:15 -0600 (CST) Subject: [Scipy-svn] r5291 - trunk Message-ID: <20081227113115.106F2C7C02B@scipy.org> Author: jarrod.millman Date: 2008-12-27 05:31:13 -0600 (Sat, 27 Dec 2008) New Revision: 5291 Modified: trunk/THANKS.txt Log: added Per Modified: trunk/THANKS.txt =================================================================== --- trunk/THANKS.txt 2008-12-27 00:46:24 UTC (rev 5290) +++ trunk/THANKS.txt 2008-12-27 11:31:13 UTC (rev 5291) @@ -50,6 +50,7 @@ Tiziano Zito for generalized symmetric and hermitian eigenvalue problem solver. Chris Burns for bug-fixes. +Per Brodtkorb for improvements to stats distributions Institutions ------------ From scipy-svn at scipy.org Sat Dec 27 16:44:25 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 27 Dec 2008 15:44:25 -0600 (CST) Subject: [Scipy-svn] r5292 - in trunk/scipy/sparse: . tests Message-ID: <20081227214425.CB19BC7C009@scipy.org> Author: wnbell Date: 2008-12-27 15:44:20 -0600 (Sat, 27 Dec 2008) New Revision: 5292 Modified: trunk/scipy/sparse/construct.py trunk/scipy/sparse/tests/test_construct.py Log: fixed sparse.eye() with k != 0 resolves ticket #825 Modified: trunk/scipy/sparse/construct.py =================================================================== --- trunk/scipy/sparse/construct.py 2008-12-27 11:31:13 UTC (rev 5291) +++ trunk/scipy/sparse/construct.py 2008-12-27 21:44:20 UTC (rev 5292) @@ -99,14 +99,16 @@ else: return identity(n, dtype=dtype, format='csr').asformat(format) + def eye(m, n, k=0, dtype='d', format=None): """eye(m, n) returns a sparse (m x n) matrix where the k-th diagonal is all ones and everything else is zeros. """ m,n = int(m),int(n) - diags = np.ones((1, min(m,n)), dtype=dtype) + diags = np.ones((1, min(m + k, n)), dtype=dtype) return spdiags(diags, k, m, n).asformat(format) + def kron(A, B, format=None): """kronecker product of sparse matrices A and B Modified: trunk/scipy/sparse/tests/test_construct.py =================================================================== --- trunk/scipy/sparse/tests/test_construct.py 2008-12-27 11:31:13 UTC (rev 5291) +++ trunk/scipy/sparse/tests/test_construct.py 2008-12-27 21:44:20 UTC (rev 5292) @@ -1,6 +1,6 @@ """test sparse matrix construction functions""" -import numpy +import numpy as np from numpy import array, matrix from numpy.testing import * @@ -83,6 +83,16 @@ assert_equal(eye(3,3,dtype='int16').dtype, 'int16') + assert_equal(eye(3, 4, -4).toarray(), np.eye(3, 4, -4)) + assert_equal(eye(3, 4, -3).toarray(), np.eye(3, 4, -3)) + assert_equal(eye(3, 4, -2).toarray(), np.eye(3, 4, -2)) + assert_equal(eye(3, 4, -1).toarray(), np.eye(3, 4, -1)) + assert_equal(eye(3, 4, 0).toarray(), np.eye(3, 4, 0)) + assert_equal(eye(3, 4, 1).toarray(), np.eye(3, 4, 1)) + assert_equal(eye(3, 4, 2).toarray(), np.eye(3, 4, 2)) + assert_equal(eye(3, 4, 3).toarray(), np.eye(3, 4, 3)) + assert_equal(eye(3, 4, 4).toarray(), np.eye(3, 4, 4)) + def test_kron(self): cases = [] @@ -103,7 +113,7 @@ for a in cases: for b in cases: result = kron(csr_matrix(a),csr_matrix(b)).todense() - expected = numpy.kron(a,b) + expected = np.kron(a,b) assert_array_equal(result,expected) def test_kronsum(self): @@ -121,8 +131,8 @@ for a in cases: for b in cases: result = kronsum(csr_matrix(a),csr_matrix(b)).todense() - expected = numpy.kron(numpy.eye(len(b)), a) + \ - numpy.kron(b, numpy.eye(len(a))) + expected = np.kron(np.eye(len(b)), a) + \ + np.kron(b, np.eye(len(a))) assert_array_equal(result,expected) def test_vstack(self): From scipy-svn at scipy.org Sat Dec 27 16:53:03 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 27 Dec 2008 15:53:03 -0600 (CST) Subject: [Scipy-svn] r5293 - in trunk/scipy/sparse: . tests Message-ID: <20081227215303.79C6AC7C009@scipy.org> Author: wnbell Date: 2008-12-27 15:52:58 -0600 (Sat, 27 Dec 2008) New Revision: 5293 Modified: trunk/scipy/sparse/construct.py trunk/scipy/sparse/tests/test_construct.py Log: fixed other bugs in sparse.eye Modified: trunk/scipy/sparse/construct.py =================================================================== --- trunk/scipy/sparse/construct.py 2008-12-27 21:44:20 UTC (rev 5292) +++ trunk/scipy/sparse/construct.py 2008-12-27 21:52:58 UTC (rev 5293) @@ -105,7 +105,7 @@ is all ones and everything else is zeros. """ m,n = int(m),int(n) - diags = np.ones((1, min(m + k, n)), dtype=dtype) + diags = np.ones((1, max(0, min(m + k, n))), dtype=dtype) return spdiags(diags, k, m, n).asformat(format) Modified: trunk/scipy/sparse/tests/test_construct.py =================================================================== --- trunk/scipy/sparse/tests/test_construct.py 2008-12-27 21:44:20 UTC (rev 5292) +++ trunk/scipy/sparse/tests/test_construct.py 2008-12-27 21:52:58 UTC (rev 5293) @@ -83,15 +83,10 @@ assert_equal(eye(3,3,dtype='int16').dtype, 'int16') - assert_equal(eye(3, 4, -4).toarray(), np.eye(3, 4, -4)) - assert_equal(eye(3, 4, -3).toarray(), np.eye(3, 4, -3)) - assert_equal(eye(3, 4, -2).toarray(), np.eye(3, 4, -2)) - assert_equal(eye(3, 4, -1).toarray(), np.eye(3, 4, -1)) - assert_equal(eye(3, 4, 0).toarray(), np.eye(3, 4, 0)) - assert_equal(eye(3, 4, 1).toarray(), np.eye(3, 4, 1)) - assert_equal(eye(3, 4, 2).toarray(), np.eye(3, 4, 2)) - assert_equal(eye(3, 4, 3).toarray(), np.eye(3, 4, 3)) - assert_equal(eye(3, 4, 4).toarray(), np.eye(3, 4, 4)) + for m in [3, 5]: + for n in [3, 5]: + for k in range(-5,6): + assert_equal(eye(m, n, k=k).toarray(), np.eye(m, n, k=k)) def test_kron(self): cases = [] From scipy-svn at scipy.org Sat Dec 27 18:34:17 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Sat, 27 Dec 2008 17:34:17 -0600 (CST) Subject: [Scipy-svn] r5294 - in trunk/scipy/sparse: . tests Message-ID: <20081227233417.0B005C7C009@scipy.org> Author: wnbell Date: 2008-12-27 17:34:08 -0600 (Sat, 27 Dec 2008) New Revision: 5294 Modified: trunk/scipy/sparse/base.py trunk/scipy/sparse/tests/test_base.py Log: check for matrix dimensions in sparse * sparse Modified: trunk/scipy/sparse/base.py =================================================================== --- trunk/scipy/sparse/base.py 2008-12-27 21:52:58 UTC (rev 5293) +++ trunk/scipy/sparse/base.py 2008-12-27 23:34:08 UTC (rev 5294) @@ -283,6 +283,8 @@ return self._mul_scalar(other) if issparse(other): + if self.shape[1] != other.shape[0]: + raise ValueError('dimension mismatch') return self._mul_sparse_matrix(other) try: Modified: trunk/scipy/sparse/tests/test_base.py =================================================================== --- trunk/scipy/sparse/tests/test_base.py 2008-12-27 21:52:58 UTC (rev 5293) +++ trunk/scipy/sparse/tests/test_base.py 2008-12-27 23:34:08 UTC (rev 5294) @@ -446,6 +446,12 @@ assert_array_almost_equal(B.todense(), A.todense() * A.T.todense()) assert_array_almost_equal(B.todense(), A.todense() * A.todense().T) + + # check dimension mismatch 2x2 times 3x2 + A = self.spmatrix( [[1,2],[3,4]] ) + B = self.spmatrix( [[1,2],[3,4],[5,6]] ) + assert_raises(ValueError, A.__mul__, B) + def test_matmat_dense(self): a = matrix([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]]) asp = self.spmatrix(a) From scipy-svn at scipy.org Mon Dec 29 01:04:24 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Mon, 29 Dec 2008 00:04:24 -0600 (CST) Subject: [Scipy-svn] r5295 - trunk/doc/release Message-ID: <20081229060424.280E7C7C007@scipy.org> Author: cdavid Date: 2008-12-29 00:04:19 -0600 (Mon, 29 Dec 2008) New Revision: 5295 Modified: trunk/doc/release/0.7.0-notes.rst Log: Add python 2.6 notes in the scipy 0.7.0 release notes. Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-27 23:34:08 UTC (rev 5294) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-29 06:04:19 UTC (rev 5295) @@ -238,3 +238,20 @@ Support for NumScons has been added. NumScons is a tentative new build system for NumPy/SciPy, using scons at its core. + +Python 2.6 and 3.0 +------------------ + +Python 3.0 is not supported at all: it requires numpy to be ported to python +3.0, which is a massive effort, since a lot of C code has to be ported. It will +happen, but not anytime soon. + +The main issue with 2.6 support is numpy. On Unix (including Mac OS X), numpy +1.2.1 mostly works, with a few caveats. On windows, there are some problems +related to the compilation process. The upcoming 1.3 version of numpy will fix +those. Then, because of some python 2.6 bugs, f2py does not work on python 2.6; +the fixes will also be in the upcoming numpy 1.3. + +The bottom line: if you can avoid it, do not use python 2.6 yet for +numpy/scipy. If you really need scipy on python 2.6, then it is recommended +have to build numpy from svn by yourself, and then build scipy. From scipy-svn at scipy.org Tue Dec 30 08:49:23 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 07:49:23 -0600 (CST) Subject: [Scipy-svn] r5296 - trunk/scipy/special Message-ID: <20081230134923.F2F3FC7C00B@scipy.org> Author: jarrod.millman Date: 2008-12-30 07:49:22 -0600 (Tue, 30 Dec 2008) New Revision: 5296 Modified: trunk/scipy/special/orthogonal.py Log: clarified relationship to NR code as explained on the maling list by Chuck Harris, Alan Isaac, and Fernando Perez Modified: trunk/scipy/special/orthogonal.py =================================================================== --- trunk/scipy/special/orthogonal.py 2008-12-29 06:04:19 UTC (rev 5295) +++ trunk/scipy/special/orthogonal.py 2008-12-30 13:49:22 UTC (rev 5296) @@ -34,8 +34,9 @@ P_0(x) = 1 P_-1(x) == 0 -See Numerical Recipies in C, page 156 and -Abramowitz and Stegun p. 774, 782 +For a more detailed discussion see Numerical Recipies in C (p. 156) and +Abramowitz and Stegun (p. 774, 782); while our implementation differs, the +algorithm and formulas are similar. Functions: From scipy-svn at scipy.org Tue Dec 30 08:52:32 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 07:52:32 -0600 (CST) Subject: [Scipy-svn] r5297 - trunk/scipy/optimize Message-ID: <20081230135232.ECF07C7C00B@scipy.org> Author: jarrod.millman Date: 2008-12-30 07:52:27 -0600 (Tue, 30 Dec 2008) New Revision: 5297 Modified: trunk/scipy/optimize/zeros.py Log: clean up text Modified: trunk/scipy/optimize/zeros.py =================================================================== --- trunk/scipy/optimize/zeros.py 2008-12-30 13:49:22 UTC (rev 5296) +++ trunk/scipy/optimize/zeros.py 2008-12-30 13:52:27 UTC (rev 5297) @@ -141,9 +141,9 @@ ----- Uses [Ridders1979]_ method to find a zero of the function `f` between the arguments `a` and `b`. Ridders' method is faster than bisection, but not - generaly as fast as the brent rountines. [Ridders1979]_ provides the + generally as fast as the Brent rountines. [Ridders1979]_ provides the classic description and source of the algorithm. A description can also be - found in may be found in any recent edition of Numerical Recipes. + found in any recent edition of Numerical Recipes. The routine used here diverges slightly from standard presentations in order to be a bit more careful of tolerance. @@ -180,7 +180,7 @@ claims convergence is guaranteed for functions computable within [a,b]. [Brent1973]_ provides the classic description of the algorithm. Another - description is in any recent edition of Numerical Recipes, including + description can be found in a recent edition of Numerical Recipes, including [PressEtal1992]_. Another description is at http://mathworld.wolfram.com/BrentsMethod.html. It should be easy to understand the algorithm just by reading our code. Our code diverges a bit From scipy-svn at scipy.org Tue Dec 30 09:52:33 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 08:52:33 -0600 (CST) Subject: [Scipy-svn] r5298 - trunk/doc/release Message-ID: <20081230145233.8E72FC7C00B@scipy.org> Author: jarrod.millman Date: 2008-12-30 08:52:31 -0600 (Tue, 30 Dec 2008) New Revision: 5298 Modified: trunk/doc/release/0.7.0-notes.rst Log: working on release notes Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-30 13:52:27 UTC (rev 5297) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-30 14:52:31 UTC (rev 5298) @@ -2,10 +2,36 @@ SciPy 0.7.0 Release Notes ========================= -This is a new stable release. Please note that unlike previous versions -of SciPy, this release requires Python 2.4 or greater. This release also -requires NumPy 1.2.0 or greater. +.. contents:: +This stable release comes almost one year after the 0.6.0 release +and contains many new features, numerous bug-fixes, improved test +coverage, and better documentation. + +Please note that unlike previous versions of SciPy, this release +requires Python 2.4 or 2.5. This release also requires NumPy 1.2.0 +or greater. + +.. note:: Python 2.6 and 3.0 + + Python 3.0 is not supported at all: it requires NumPy to be ported to + Python 3.0, which is a massive effort, since a lot of C code has to be + ported. It will happen, but not anytime soon. + +The main issue with 2.6 support is numpy. On Unix (including Mac OS X), numpy +1.2.1 mostly works, with a few caveats. On windows, there are some problems +related to the compilation process. The upcoming 1.3 version of numpy will fix +those. Then, because of some python 2.6 bugs, f2py does not work on python 2.6; +the fixes will also be in the upcoming numpy 1.3. + +The bottom line: if you can avoid it, do not use python 2.6 yet for +numpy/scipy. If you really need scipy on python 2.6, then it is recommended +have to build numpy from svn by yourself, and then build scipy. + +License review +~~~~~~~~~~~~~~ + + Changes ------- @@ -192,8 +218,8 @@ Users of ``scipy.interpolate.interp1d`` may need to revise their code if it relies on the incorrect behavior. -Bug fixes in the stats package -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Statistics package +~~~~~~~~~~~~~~~~~~ Statistical functions for masked arrays have been added and are accessible through scipy.stats.mstats. The functions are similar to their counterparts @@ -239,19 +265,13 @@ Support for NumScons has been added. NumScons is a tentative new build system for NumPy/SciPy, using scons at its core. -Python 2.6 and 3.0 ------------------- +Sandbox Removed +~~~~~~~~~~~~~~~ -Python 3.0 is not supported at all: it requires numpy to be ported to python -3.0, which is a massive effort, since a lot of C code has to be ported. It will -happen, but not anytime soon. - -The main issue with 2.6 support is numpy. On Unix (including Mac OS X), numpy -1.2.1 mostly works, with a few caveats. On windows, there are some problems -related to the compilation process. The upcoming 1.3 version of numpy will fix -those. Then, because of some python 2.6 bugs, f2py does not work on python 2.6; -the fixes will also be in the upcoming numpy 1.3. - -The bottom line: if you can avoid it, do not use python 2.6 yet for -numpy/scipy. If you really need scipy on python 2.6, then it is recommended -have to build numpy from svn by yourself, and then build scipy. +While porting SciPy to NumPy in 2005, several packages and modules were moved into +``scipy.sandbox``. The sandbox was a staging ground for packages that were undergoing +rapid development and whose APIs were in flux. It was also a place where broken code +could live. The sandbox has served its purpose well and was starting to create confusion, +so ``scipy.sandbox`` was removed. Most of the code was moved into ``scipy``, some code was +made into a ``scikit``, and the remaining code was just deleted as the functionality had +been replaced by other code. From scipy-svn at scipy.org Tue Dec 30 10:01:20 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 09:01:20 -0600 (CST) Subject: [Scipy-svn] r5299 - trunk/doc/release Message-ID: <20081230150120.8A258C7C00B@scipy.org> Author: jarrod.millman Date: 2008-12-30 09:01:17 -0600 (Tue, 30 Dec 2008) New Revision: 5299 Modified: trunk/doc/release/0.7.0-notes.rst Log: formatting fixes Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-30 14:52:31 UTC (rev 5298) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-30 15:01:17 UTC (rev 5299) @@ -12,26 +12,19 @@ requires Python 2.4 or 2.5. This release also requires NumPy 1.2.0 or greater. -.. note:: Python 2.6 and 3.0 +Python 2.6 and 3.0 +~~~~~~~~~~~~~~~~~~ - Python 3.0 is not supported at all: it requires NumPy to be ported to - Python 3.0, which is a massive effort, since a lot of C code has to be - ported. It will happen, but not anytime soon. +Python 3.0 is not supported at all: it requires NumPy to be ported to +Python 3.0, which is a massive effort, since a lot of C code has to be +ported. It will happen, but not anytime soon. -The main issue with 2.6 support is numpy. On Unix (including Mac OS X), numpy -1.2.1 mostly works, with a few caveats. On windows, there are some problems -related to the compilation process. The upcoming 1.3 version of numpy will fix -those. Then, because of some python 2.6 bugs, f2py does not work on python 2.6; -the fixes will also be in the upcoming numpy 1.3. +The main issue with 2.6 support is NumPy. On UNIX (including Mac OS X), NumPy +1.2.1 mostly works, with a few caveats. On Windows, there are some problems +related to the compilation process. The upcoming 1.3 version of NumPy will fix +those. Then, because of some Python 2.6 bugs, ``f2py`` does not work on Python +2.6; the fixes will also be in the upcoming NumPy 1.3. -The bottom line: if you can avoid it, do not use python 2.6 yet for -numpy/scipy. If you really need scipy on python 2.6, then it is recommended -have to build numpy from svn by yourself, and then build scipy. - -License review -~~~~~~~~~~~~~~ - - Changes ------- From scipy-svn at scipy.org Tue Dec 30 10:04:00 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 09:04:00 -0600 (CST) Subject: [Scipy-svn] r5300 - trunk/doc/release Message-ID: <20081230150400.57174C7C00B@scipy.org> Author: jarrod.millman Date: 2008-12-30 09:03:59 -0600 (Tue, 30 Dec 2008) New Revision: 5300 Modified: trunk/doc/release/0.7.0-notes.rst Log: more formatting Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-30 15:01:17 UTC (rev 5299) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-30 15:03:59 UTC (rev 5300) @@ -13,7 +13,7 @@ or greater. Python 2.6 and 3.0 -~~~~~~~~~~~~~~~~~~ +------------------ Python 3.0 is not supported at all: it requires NumPy to be ported to Python 3.0, which is a massive effort, since a lot of C code has to be @@ -25,11 +25,8 @@ those. Then, because of some Python 2.6 bugs, ``f2py`` does not work on Python 2.6; the fixes will also be in the upcoming NumPy 1.3. -Changes -------- - Sparse Matrices -~~~~~~~~~~~~~~~ +--------------- * added support for integer dtypes such ``int8``, ``uint32``, etc. * new class ``dia_matrix`` : the sparse DIAgonal format @@ -69,7 +66,7 @@ * numerous bugfixes Reworking of IO package -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- The IO code in both NumPy and SciPy is undergoing a major reworking. NumPy will be where basic code for reading and writing NumPy arrays is located, @@ -89,7 +86,7 @@ * string arrays have ``dtype='U...'`` instead of ``dtype=object`` New Hierarchical Clustering module -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------------------------- This module adds new hierarchical clustering functionality to the ``scipy.cluster`` package. The function interfaces are similar to the @@ -113,7 +110,7 @@ matplotlib. New Spatial package -~~~~~~~~~~~~~~~~~~~ +------------------- Collection of spatial algorithms and data structures useful for spatial statistics and clustering applications. Includes fast compiled code for @@ -139,14 +136,14 @@ distance matrices between square and condensed forms. Reworked fftpack package -~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------ FFTW2, FFTW3, MKL and DJBFFT wrappers have been removed. Only (NETLIB) fftpack remains. By focusing on one backend, we hope to add new features -- like float32 support -- more easily. New Constants package -~~~~~~~~~~~~~~~~~~~~~ +--------------------- ``scipy.constants`` provides a collection of physical constants and conversion factors. These constants are taken from CODATA Recommended @@ -160,7 +157,7 @@ for everyday use. New Radial Basis Function module -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------------- ``scipy.interpolate`` now contains a Radial Basis Function module. Radial basis functions can be used for smoothing/interpolating scattered @@ -168,14 +165,14 @@ outside of the observed data range. New complex ODE integrator -~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------- ``scipy.integrate.ode`` now contains a wrapper for the ZVODE complex-valued ordinary differential equation solver (by Peter N. Brown, Alan C. Hindmarsh, and George D. Byrne). New generalized symmetric and hermitian eigenvalue problem solver -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------------------------------------------------------------- ``scipy.linalg.eigh`` now contains wrappers for more LAPACK symmetric and hermitian eigenvalue problem solvers. Users @@ -185,7 +182,7 @@ changed accordingly. Major documentation improvements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------------- Scipy documentation is now more accessible than previously; you can view a HTML reference manual online at http://docs.scipy.org/ or @@ -199,7 +196,7 @@ documentation editor at http://docs.scipy.org/ and correct the issues. Bug fixes in the interpolation package -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------------------- The shape of return values from ``scipy.interpolate.interp1d`` used to be incorrect if interpolated data had more than 2 dimensions and @@ -212,7 +209,7 @@ if it relies on the incorrect behavior. Statistics package -~~~~~~~~~~~~~~~~~~ +------------------ Statistical functions for masked arrays have been added and are accessible through scipy.stats.mstats. The functions are similar to their counterparts @@ -237,7 +234,7 @@ release of scipy. Running Tests -~~~~~~~~~~~~~ +------------- NumPy 1.2 introduced a new testing framework based on `nose `__. Starting with this release SciPy now @@ -253,13 +250,13 @@ `__. Building SciPy -~~~~~~~~~~~~~~ +-------------- Support for NumScons has been added. NumScons is a tentative new build system for NumPy/SciPy, using scons at its core. Sandbox Removed -~~~~~~~~~~~~~~~ +--------------- While porting SciPy to NumPy in 2005, several packages and modules were moved into ``scipy.sandbox``. The sandbox was a staging ground for packages that were undergoing From scipy-svn at scipy.org Tue Dec 30 14:08:40 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 13:08:40 -0600 (CST) Subject: [Scipy-svn] r5301 - trunk/scipy/stats Message-ID: <20081230190840.F41DFC7C00B@scipy.org> Author: josef Date: 2008-12-30 13:08:36 -0600 (Tue, 30 Dec 2008) New Revision: 5301 Modified: trunk/scipy/stats/stats.py Log: fix 2 pvalues that are calculated at the wrong tail Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-30 15:03:59 UTC (rev 5300) +++ trunk/scipy/stats/stats.py 2008-12-30 19:08:36 UTC (rev 5301) @@ -886,7 +886,7 @@ alpha = math.sqrt(2.0/(W2-1)) y = np.where(y==0, 1, y) Z = delta*np.log(y/alpha + np.sqrt((y/alpha)**2+1)) - return Z, (1.0 - zprob(Z))*2 + return Z, (1.0 - zprob(np.abs(Z)))*2 def kurtosistest(a, axis=0): @@ -928,7 +928,8 @@ if Z.ndim == 0: Z = Z[()] #JPNote: p-value sometimes larger than 1 - return Z, (1.0-zprob(Z))*2 + #zprob uses upper tail, so Z needs to be positive + return Z, (1.0-zprob(np.abs(Z)))*2 def normaltest(a, axis=0): From scipy-svn at scipy.org Tue Dec 30 18:30:46 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 17:30:46 -0600 (CST) Subject: [Scipy-svn] r5302 - in trunk: doc/source scipy/fftpack scipy/stats Message-ID: <20081230233046.A397EC7C00B@scipy.org> Author: ptvirtan Date: 2008-12-30 17:30:23 -0600 (Tue, 30 Dec 2008) New Revision: 5302 Modified: trunk/doc/source/interpolate.rst trunk/doc/source/optimize.rst trunk/doc/source/special.rst trunk/doc/source/stats.mstats.rst trunk/doc/source/stats.rst trunk/scipy/fftpack/basic.py trunk/scipy/stats/distributions.py trunk/scipy/stats/info.py trunk/scipy/stats/stats.py Log: Merge from doc wiki Modified: trunk/doc/source/interpolate.rst =================================================================== --- trunk/doc/source/interpolate.rst 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/doc/source/interpolate.rst 2008-12-30 23:30:23 UTC (rev 5302) @@ -39,6 +39,20 @@ InterpolatedUnivariateSpline LSQUnivariateSpline +The above univariate spline classes have the following methods: + +.. autosummary:: + :toctree: generated/ + + UnivariateSpline.__call__ + UnivariateSpline.derivatives + UnivariateSpline.integral + UnivariateSpline.roots + UnivariateSpline.get_coeffs + UnivariateSpline.get_knots + UnivariateSpline.get_residual + UnivariateSpline.set_smoothing_factor + Low-level interface to FITPACK functions: .. autosummary:: Modified: trunk/doc/source/optimize.rst =================================================================== --- trunk/doc/source/optimize.rst 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/doc/source/optimize.rst 2008-12-30 23:30:23 UTC (rev 5302) @@ -30,6 +30,7 @@ fmin_l_bfgs_b fmin_tnc fmin_cobyla + nnls Global ------ Modified: trunk/doc/source/special.rst =================================================================== --- trunk/doc/source/special.rst 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/doc/source/special.rst 2008-12-30 23:30:23 UTC (rev 5302) @@ -299,8 +299,18 @@ weights, and total weights for the appropriate form of Gaussian quadrature. These are returned in an n x 3 array with roots in the first column, weights in the second column, and total weights -in the final column +in the final column. +.. warning:: + + Evaluating large-order polynomials using these functions can be + numerically unstable. + + The reason is that the functions below return polynomials as + `numpy.poly1d` objects, which represent the polynomial in terms + of their coefficients, and this can result to loss of precision + when the polynomial terms are summed. + .. autosummary:: :toctree: generated/ Modified: trunk/doc/source/stats.mstats.rst =================================================================== --- trunk/doc/source/stats.mstats.rst 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/doc/source/stats.mstats.rst 2008-12-30 23:30:23 UTC (rev 5302) @@ -14,69 +14,68 @@ .. autosummary:: :toctree: generated/ - -argstoarray -betai -chisquare -count_tied_groups -describe -f_oneway -f_value_wilks_lambda -find_repeats -friedmanchisquare -gmean -hmean -kendalltau -kendalltau_seasonal -kruskalwallis -kruskalwallis -ks_twosamp -ks_twosamp -kurtosis -kurtosistest -linregress -mannwhitneyu -plotting_positions -mode -moment -mquantiles -msign -normaltest -obrientransform -pearsonr -plotting_positions -pointbiserialr -rankdata -samplestd -samplevar -scoreatpercentile -sem -signaltonoise -skew -skewtest -spearmanr -std -stderr -theilslopes -threshold -tmax -tmean -tmin -trim -trima -trimboth -trimmed_stde -trimr -trimtail -tsem -ttest_onesamp -ttest_ind -ttest_onesamp -ttest_rel -tvar -var -variation -winsorize -z -zmap -zs + argstoarray + betai + chisquare + count_tied_groups + describe + f_oneway + f_value_wilks_lambda + find_repeats + friedmanchisquare + gmean + hmean + kendalltau + kendalltau_seasonal + kruskalwallis + kruskalwallis + ks_twosamp + ks_twosamp + kurtosis + kurtosistest + linregress + mannwhitneyu + plotting_positions + mode + moment + mquantiles + msign + normaltest + obrientransform + pearsonr + plotting_positions + pointbiserialr + rankdata + samplestd + samplevar + scoreatpercentile + sem + signaltonoise + skew + skewtest + spearmanr + std + stderr + theilslopes + threshold + tmax + tmean + tmin + trim + trima + trimboth + trimmed_stde + trimr + trimtail + tsem + ttest_onesamp + ttest_ind + ttest_onesamp + ttest_rel + tvar + var + variation + winsorize + z + zmap + zs Modified: trunk/doc/source/stats.rst =================================================================== --- trunk/doc/source/stats.rst 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/doc/source/stats.rst 2008-12-30 23:30:23 UTC (rev 5302) @@ -143,6 +143,9 @@ Statistical functions ===================== +Several of these functions have a similar version in scipy.stats.mstats +which work for masked arrays. + .. autosummary:: :toctree: generated/ @@ -261,6 +264,13 @@ ppcc_max ppcc_plot +Univariate and multivariate kernel density estimation (:mod:`scipy.stats.kde`) +============================================================================== +.. autosummary:: + :toctree: generated/ + + gaussian_kde + For many more stat related functions install the software R and the interface package rpy. Modified: trunk/scipy/fftpack/basic.py =================================================================== --- trunk/scipy/fftpack/basic.py 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/scipy/fftpack/basic.py 2008-12-30 23:30:23 UTC (rev 5302) @@ -55,31 +55,53 @@ def fft(x, n=None, axis=-1, overwrite_x=0): - """ fft(x, n=None, axis=-1, overwrite_x=0) -> y - + """ Return discrete Fourier transform of arbitrary type sequence x. - The returned complex array contains - [y(0),y(1),..,y(n/2-1),y(-n/2),...,y(-1)] if n is even - [y(0),y(1),..,y((n-1)/2),y(-(n-1)/2),...,y(-1)] if n is odd - where - y(j) = sum[k=0..n-1] x[k] * exp(-sqrt(-1)*j*k* 2*pi/n) - j = 0..n-1 - Note that y(-j) = y(n-j). - - Optional input: - n - Defines the length of the Fourier transform. If n is not - specified then n=x.shape[axis] is set. If nx.shape[axis], x is zero-padded. - axis - The transform is applied along the given axis of the input - array (or the newly constructed array if n argument was used). - overwrite_x - If set to true, the contents of x can be destroyed. + (Default n=x.shape[axis]). + axis : int, optional + Axis along which the fft's are computed. (default=-1) + overwrite_x : bool, optional + If True the contents of x can be destroyed. (default=False) - Notes: - y == fft(ifft(y)) within numerical accuracy. + Returns + ------- + z : complex ndarray + with the elements: + [y(0),y(1),..,y(n/2-1),y(-n/2),...,y(-1)] if n is even + [y(0),y(1),..,y((n-1)/2),y(-(n-1)/2),...,y(-1)] if n is odd + where + y(j) = sum[k=0..n-1] x[k] * exp(-sqrt(-1)*j*k* 2*pi/n), j = 0..n-1 + Note that y(-j) = y(n-j). + + See Also + -------- + ifft : Inverse FFT + rfft : FFT of a real sequence + + Notes + ----- + The packing of the result is "standard": If A = fft(a, n), then A[0] + contains the zero-frequency term, A[1:n/2+1] contains the + positive-frequency terms, and A[n/2+1:] contains the negative-frequency + terms, in order of decreasingly negative frequency. So for an 8-point + transform, the frequencies of the result are [ 0, 1, 2, 3, 4, -3, -2, -1]. + + This is most efficient for n a power of two. + + Examples + -------- + >>> x = np.arange(5) + >>> np.all(np.abs(x-fft(ifft(x))<1.e-15) #within numerical accuracy. + True + """ tmp = asarray(x) if istype(tmp, numpy.complex128): Modified: trunk/scipy/stats/distributions.py =================================================================== --- trunk/scipy/stats/distributions.py 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/scipy/stats/distributions.py 2008-12-30 23:30:23 UTC (rev 5302) @@ -275,18 +275,26 @@ # These are actually called, and should not be overwritten if you # want to keep error checking. def rvs(self,*args,**kwds): - """Random variates of given type. + """ + Random variates of given type. - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) + size : int or tuple of ints, optional + defining number of random variates (default=1) - **kwds - ====== - size - number of random variates (default=1) - loc - location parameter (default=0) - scale - scale parameter (default=1) + Returns + ------- + rvs : array-like + random variates of given `size` + """ kwd_names = ['loc', 'scale', 'size', 'discrete'] loc, scale, size, discrete = map(kwds.get, kwd_names, @@ -322,18 +330,17 @@ class rv_continuous(rv_generic): - """A Generic continuous random variable. + """ + A Generic continuous random variable. - Continuous random variables are defined from a standard form chosen - for simplicity of representation. The standard form may require - some shape parameters to complete its specification. The distributions - also take optional location and scale parameters using loc= and scale= - keywords (defaults: loc=0, scale=1) + Continuous random variables are defined from a standard form and may + require some shape parameters to complete its specification. Any + optional keyword parameters can be passed to the methods of the RV + object as given below: - These shape, scale, and location parameters can be passed to any of the - methods of the RV object such as the following: - - generic.rvs(,loc=0,scale=1) + Methods + ------- + generic.rvs(,loc=0,scale=1,size=1) - random variates generic.pdf(x,,loc=0,scale=1) @@ -352,18 +359,60 @@ - inverse survival function (inverse of sf) generic.stats(,loc=0,scale=1,moments='mv') - - mean('m',axis=0), variance('v'), skew('s'), and/or kurtosis('k') + - mean('m'), variance('v'), skew('s'), and/or kurtosis('k') generic.entropy(,loc=0,scale=1) - (differential) entropy of the RV. - Alternatively, the object may be called (as a function) to fix - the shape, location, and scale parameters returning a - "frozen" continuous RV object: + generic.fit(data,,loc=0,scale=1) + - Parameter estimates for generic data - myrv = generic(,loc=0,scale=1) - - frozen RV object with the same methods but holding the - given shape, location, and scale fixed + Alternatively, the object may be called (as a function) to fix the shape, + location, and scale parameters returning a "frozen" continuous RV object: + + rv = generic(,loc=0,scale=1) + - frozen RV object with the same methods but holding the given shape, location, and scale fixed + + Parameters + ---------- + x : array-like + quantiles + q : array-like + lower or upper tail probability + : array-like + shape parameters + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) + size : int or tuple of ints, optional + shape of random variates (default computed from input arguments ) + moments : string, optional + composed of letters ['mvsk'] specifying which moments to compute where + 'm' = mean, 'v' = variance, 's' = (Fisher's) skew and + 'k' = (Fisher's) kurtosis. (default='mv') + + Examples + -------- + >>> import matplotlib.pyplot as plt + >>> numargs = generic.numargs + >>> [ ] = [0.9,]*numargs + >>> rv = generic() + + Display frozen pdf + + >>> x = np.linspace(0,np.minimum(rv.dist.b,3)) + >>> h=plt.plot(x,rv.pdf(x)) + + Check accuracy of cdf and ppf + + >>> prb = generic.cdf(x,) + >>> h=plt.semilogy(np.abs(x-generic.ppf(prb,c))+1e-20) + + Random number generation + + >>> R = generic.rvs(,size=100) + """ def __init__(self, momtype=1, a=None, b=None, xa=-10.0, xb=10.0, xtol=1e-14, badvalue=None, name=None, longname=None, @@ -496,17 +545,26 @@ return self.generic_moment(n,*args) def pdf(self,x,*args,**kwds): - """Probability density function at x of the given RV. + """ + Probability density function at x of the given RV. - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + x : array-like + quantiles + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) - **kwds - ====== - loc - location parameter (default=0) - scale - scale parameter (default=1) + Returns + ------- + pdf : array-like + Probability density function evaluated at x + """ loc,scale=map(kwds.get,['loc','scale']) args, loc, scale = self._fix_loc_scale(args, loc, scale) @@ -526,17 +584,26 @@ return output def cdf(self,x,*args,**kwds): - """Cumulative distribution function at x of the given RV. + """ + Cumulative distribution function at x of the given RV. - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + x : array-like + quantiles + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) - **kwds - ====== - loc - location parameter (default=0) - scale - scale parameter (default=1) + Returns + ------- + cdf : array-like + Cumulative distribution function evaluated at x + """ loc,scale=map(kwds.get,['loc','scale']) args, loc, scale = self._fix_loc_scale(args, loc, scale) @@ -558,17 +625,26 @@ return output def sf(self,x,*args,**kwds): - """Survival function (1-cdf) at x of the given RV. + """ + Survival function (1-cdf) at x of the given RV. - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + x : array-like + quantiles + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) - **kwds - ====== - loc - location parameter (default=0) - scale - scale parameter (default=1) + Returns + ------- + sf : array-like + Survival function evaluated at x + """ loc,scale=map(kwds.get,['loc','scale']) args, loc, scale = self._fix_loc_scale(args, loc, scale) @@ -589,17 +665,26 @@ return output def ppf(self,q,*args,**kwds): - """Percent point function (inverse of cdf) at q of the given RV. + """ + Percent point function (inverse of cdf) at q of the given RV. - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + q : array-like + lower tail probability + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) - **kwds - ====== - loc - location parameter (default=0) - scale - scale parameter (default=1) + Returns + ------- + x : array-like + quantile corresponding to the lower tail probability q. + """ loc,scale=map(kwds.get,['loc','scale']) args, loc, scale = self._fix_loc_scale(args, loc, scale) @@ -621,17 +706,26 @@ return output def isf(self,q,*args,**kwds): - """Inverse survival function at q of the given RV. + """ + Inverse survival function at q of the given RV. - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + q : array-like + upper tail probability + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) - **kwds - ====== - loc - location parameter (default=0) - scale - scale parameter (default=1) + Returns + ------- + x : array-like + quantile corresponding to the upper tail probability q. + """ loc,scale=map(kwds.get,['loc','scale']) args, loc, scale = self._fix_loc_scale(args, loc, scale) @@ -654,23 +748,32 @@ return output def stats(self,*args,**kwds): - """Some statistics of the given RV + """ + Some statistics of the given RV - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) - **kwds - ====== - loc - location parameter (default=0) - scale - scale parameter (default=1) - moments - a string composed of letters ['mvsk'] specifying - which moments to compute (default='mv') - 'm' = mean, - 'v' = variance, - 's' = (Fisher's) skew, - 'k' = (Fisher's) kurtosis. + moments : string, optional + composed of letters ['mvsk'] defining which moments to compute: + 'm' = mean, + 'v' = variance, + 's' = (Fisher's) skew, + 'k' = (Fisher's) kurtosis. + (default='mv') + + Returns + ------- + stats : sequence + of requested moments. + """ loc,scale,moments=map(kwds.get,['loc','scale','moments']) @@ -767,13 +870,15 @@ return tuple(output) def moment(self, n, *args): - """n'th non-central moment of distribution + """ + n'th order non-central moment of distribution - Parameters: - ----------- + Parameters + ---------- n: int, n>=1 + order of moment - *args: + arg1, arg2, arg3,... : array-like The shape parameter(s) for the distribution (see docstring of the instance object for more information) @@ -883,6 +988,21 @@ def entropy(self, *args, **kwds): + """ + Differential entropy of the RV. + + + Parameters + ---------- + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + scale : array-like, optional + scale parameter (default=1) + + """ loc,scale=map(kwds.get,['loc','scale']) args, loc, scale = self._fix_loc_scale(args, loc, scale) args = tuple(map(arr,args)) @@ -3501,15 +3621,16 @@ # x_k, p(x_k) lists in initialization class rv_discrete(rv_generic): - """A generic discrete random variable. + """ + A Generic discrete random variable. - Discrete random variables are defined from a standard form. - The standard form may require some other parameters to complete - its specification. The distribution methods also take an optional location - parameter using loc= keyword. The default is loc=0. The calling form - of the methods follow: + Discrete random variables are defined from a standard form and may require + some shape parameters to complete its specification. Any optional keyword + parameters can be passed to the methods of the RV object as given below: - generic.rvs(,loc=0) + Methods + ------- + generic.rvs(,loc=0,size=1) - random variates generic.pmf(x,,loc=0) @@ -3534,17 +3655,40 @@ - entropy of the RV Alternatively, the object may be called (as a function) to fix - the shape and location parameters returning a - "frozen" discrete RV object: + the shape and location parameters returning a + "frozen" discrete RV object: myrv = generic(,loc=0) - - frozen RV object with the same methods but holding the - given shape and location fixed. + - frozen RV object with the same methods but holding the given shape and location fixed. You can construct an aribtrary discrete rv where P{X=xk} = pk by passing to the rv_discrete initialization method (through the values= keyword) a tuple of sequences (xk,pk) which describes only those values of X (xk) that occur with nonzero probability (pk). + + Examples: + --------- + >>> import matplotlib.pyplot as plt + >>> numargs = generic.numargs + >>> [ ] = ['Replace with resonable value',]*numargs + + Display frozen pmf: + >>> rv = generic() + >>> x = np.arange(0,np.min(rv.dist.b,3)+1) + >>> h = plt.plot(x,rv.pmf(x)) + + Check accuracy of cdf and ppf: + >>> prb = generic.cdf(x,) + >>> h = plt.semilogy(np.abs(x-generic.ppf(prb,))+1e-20) + + Random number generation: + >>> R = generic.rvs(,size=100) + + Custom made discrete distribution: + >>> vals = [arange(7),(0.1,0.2,0.3,0.1,0.1,0.1,0.1)] + >>> custm = rv_discrete(name='custm',values=vals) + >>> h = plt.plot(vals[0],custm.pmf(vals[0])) + """ def __init__(self, a=0, b=inf, name=None, badvalue=None, moment_tol=1e-8,values=None,inc=1,longname=None, @@ -3676,20 +3820,48 @@ def rvs(self, *args, **kwargs): + """ + Random variates of given type. + + Parameters + ---------- + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + size : int or tuple of ints, optional + defining number of random variates (default=1) + + Returns + ------- + rvs : array-like + random variates of given `size` + + """ kwargs['discrete'] = True return rv_generic.rvs(self, *args, **kwargs) def pmf(self, k,*args, **kwds): - """Probability mass function at k of the given RV. + """ + Probability mass function at k of the given RV. - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) - **kwds - ====== - loc - location parameter (default=0) + Parameters + ---------- + k : array-like + quantiles + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + + Returns + ------- + pmf : array-like + Probability mass function evaluated at k + """ loc = kwds.get('loc') args, loc = self._fix_loc(args, loc) @@ -3708,16 +3880,24 @@ return output def cdf(self, k, *args, **kwds): - """Cumulative distribution function at k of the given RV + """ + Cumulative distribution function at k of the given RV - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + k : array-like, int + quantiles + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) - **kwds - ====== - loc - location parameter (default=0) + Returns + ------- + cdf : array-like + Cumulative distribution function evaluated at k + """ loc = kwds.get('loc') args, loc = self._fix_loc(args, loc) @@ -3740,16 +3920,24 @@ return output def sf(self,k,*args,**kwds): - """Survival function (1-cdf) at k of the given RV + """ + Survival function (1-cdf) at k of the given RV - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + k : array-like + quantiles + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) - **kwds - ====== - loc - location parameter (default=0) + Returns + ------- + sf : array-like + Survival function evaluated at k + """ loc= kwds.get('loc') args, loc = self._fix_loc(args, loc) @@ -3770,16 +3958,24 @@ return output def ppf(self,q,*args,**kwds): - """Percent point function (inverse of cdf) at q of the given RV + """ + Percent point function (inverse of cdf) at q of the given RV - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + q : array-like + lower tail probability + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) - **kwds - ====== - loc - location parameter (default=0) + Returns + ------- + k : array-like + quantile corresponding to the lower tail probability, q. + """ loc = kwds.get('loc') args, loc = self._fix_loc(args, loc) @@ -3803,16 +3999,24 @@ return output def isf(self,q,*args,**kwds): - """Inverse survival function (1-sf) at q of the given RV + """ + Inverse survival function (1-sf) at q of the given RV - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + q : array-like + upper tail probability + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) - **kwds - ====== - loc - location parameter (default=0) + Returns + ------- + k : array-like + quantile corresponding to the upper tail probability, q. + """ loc = kwds.get('loc') @@ -3847,22 +4051,29 @@ return output def stats(self, *args, **kwds): - """Some statistics of the given discrete RV + """ + Some statistics of the given discrete RV - *args - ===== - The shape parameter(s) for the distribution (see docstring of the - instance object for more information) + Parameters + ---------- + arg1, arg2, arg3,... : array-like + The shape parameter(s) for the distribution (see docstring of the + instance object for more information) + loc : array-like, optional + location parameter (default=0) + moments : string, optional + composed of letters ['mvsk'] defining which moments to compute: + 'm' = mean, + 'v' = variance, + 's' = (Fisher's) skew, + 'k' = (Fisher's) kurtosis. + (default='mv') - **kwds - ====== - loc - location parameter (default=0) - moments - a string composed of letters ['mvsk'] specifying - which moments to compute (default='mv') - 'm' = mean, - 'v' = variance, - 's' = (Fisher's) skew, - 'k' = (Fisher's) kurtosis. + Returns + ------- + stats : sequence + of requested moments. + """ loc,moments=map(kwds.get,['loc','moments']) N = len(args) @@ -3949,14 +4160,14 @@ return tuple(output) def moment(self, n, *args, **kwds): # Non-central moments in standard form. - """n'th non-central moment of the distribution + """ + n'th non-central moment of the distribution - - Parameters: - ----------- + Parameters + ---------- n: int, n>=1 - - *args: + order of moment + arg1, arg2, arg3,...: array-like The shape parameter(s) for the distribution (see docstring of the instance object for more information) Modified: trunk/scipy/stats/info.py =================================================================== --- trunk/scipy/stats/info.py 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/scipy/stats/info.py 2008-12-30 23:30:23 UTC (rev 5302) @@ -9,213 +9,247 @@ For each given name the following methods are available. See docstring for rv_continuous for more information -rvs -- random variates with the distribution -pdf -- probability density function -cdf -- cummulative distribution function -sf -- survival function (1.0 - cdf) -ppf -- percent-point function (inverse of cdf) -isf -- inverse survival function -stats -- mean, variance, and optionally skew and kurtosis +:rvs: + random variates with the distribution +:pdf: + probability density function +:cdf: + cumulative distribution function +:sf: + survival function (1.0 - cdf) +:ppf: + percent-point function (inverse of cdf) +:isf: + inverse survival function +:stats: + mean, variance, and optionally skew and kurtosis Calling the instance as a function returns a frozen pdf whose shape, location, and scale parameters are fixed. +Distributions +--------------- + The distributions available with the above methods are: -CONTINUOUS (Total == 81 distributions) -=========== -norm -- Normal (Gaussian) -alpha -- Alpha -anglit -- Anglit -arcsine -- Arcsine -beta -- Beta -betaprime -- Beta Prime -bradford -- Bradford -burr -- Burr -fisk -- Fisk -cauchy -- Cauchy -chi -- Chi -chi2 -- Chi-squared -cosine -- Cosine -dgamma -- Double Gamma -dweibull -- Double Weibull -erlang -- Erlang -expon -- Exponential -exponweib -- Exponentiated Weibull -exponpow -- Exponential Power -fatiguelife -- Fatigue Life (Birnbaum-Sanders) -foldcauchy -- Folded Cauchy -f -- F (Snecdor F) -foldnorm -- Folded Normal -frechet_r -- Frechet Right Sided, Extreme Value Type II (Extreme LB) or weibull_min -frechet_l -- Frechet Left Sided, Weibull_max -genlogistic -- Generalized Logistic -genpareto -- Generalized Pareto -genexpon -- Generalized Exponential -genextreme -- Generalized Extreme Value -gausshyper -- Gauss Hypergeometric -gamma -- Gamma -gengamma -- Generalized gamma -genhalflogistic -- Generalized Half Logistic -gompertz -- Gompertz (Truncated Gumbel) -gumbel_r -- Right Sided Gumbel, Log-Weibull, Fisher-Tippett, Extreme Value Type I -gumbel_l -- Left Sided Gumbel, etc. -halfcauchy -- Half Cauchy -halflogistic -- Half Logistic -halfnorm -- Half Normal -hypsecant -- Hyperbolic Secant -invgamma -- Inverse Gamma -invnorm -- Inverse Normal -invweibull -- Inverse Weibull -johnsonsb -- Johnson SB -johnsonsu -- Johnson SU -laplace -- Laplace -logistic -- Logistic -loggamma -- Log-Gamma -loglaplace -- Log-Laplace (Log Double Exponential) -lognorm -- Log-Normal -gilbrat -- Gilbrat -lomax -- Lomax (Pareto of the second kind) -maxwell -- Maxwell -mielke -- Mielke's Beta-Kappa -nakagami -- Nakagami -ncx2 -- Non-central chi-squared -ncf -- Non-central F -t -- Student's T -nct -- Non-central Student's T -pareto -- Pareto -powerlaw -- Power-function -powerlognorm -- Power log normal -powernorm -- Power normal -rdist -- R distribution -reciprocal -- Reciprocal -rayleigh -- Rayleigh -rice -- Rice -recipinvgauss -- Reciprocal Inverse Gaussian -semicircular -- Semicircular -triang -- Triangular -truncexpon -- Truncated Exponential -truncnorm -- Truncated Normal -tukeylambda -- Tukey-Lambda -uniform -- Uniform -von_mises -- Von-Mises (Circular) -wald -- Wald -weibull_min -- Minimum Weibull (see Frechet) -weibull_max -- Maximum Weibull (see Frechet) -wrapcauchy -- Wrapped Cauchy -ksone -- Kolmogorov-Smirnov one-sided (no stats) -kstwobign -- Kolmogorov-Smirnov two-sided test for Large N (no stats) +=============== ============================================================== +Continuous (Total == 81 distributions) +============================================================================== +norm Normal (Gaussian) +alpha Alpha +anglit Anglit +arcsine Arcsine +beta Beta +betaprime Beta Prime +bradford Bradford +burr Burr +fisk Fisk +cauchy Cauchy +chi Chi +chi2 Chi-squared +cosine Cosine +dgamma Double Gamma +dweibull Double Weibull +erlang Erlang +expon Exponential +exponweib Exponentiated Weibull +exponpow Exponential Power +fatiguelife Fatigue Life (Birnbaum-Sanders) +foldcauchy Folded Cauchy +f F (Snecdor F) +foldnorm Folded Normal +frechet_r Frechet Right Sided, Extreme Value Type II (Extreme LB) or weibull_min +frechet_l Frechet Left Sided, Weibull_max +genlogistic Generalized Logistic +genpareto Generalized Pareto +genexpon Generalized Exponential +genextreme Generalized Extreme Value +gausshyper Gauss Hypergeometric +gamma Gamma +gengamma Generalized gamma +genhalflogistic Generalized Half Logistic +gompertz Gompertz (Truncated Gumbel) +gumbel_r Right Sided Gumbel, Log-Weibull, Fisher-Tippett, Extreme Value Type I +gumbel_l Left Sided Gumbel, etc. +halfcauchy Half Cauchy +halflogistic Half Logistic +halfnorm Half Normal +hypsecant Hyperbolic Secant +invgamma Inverse Gamma +invnorm Inverse Normal +invweibull Inverse Weibull +johnsonsb Johnson SB +johnsonsu Johnson SU +laplace Laplace +logistic Logistic +loggamma Log-Gamma +loglaplace Log-Laplace (Log Double Exponential) +lognorm Log-Normal +gilbrat Gilbrat +lomax Lomax (Pareto of the second kind) +maxwell Maxwell +mielke Mielke's Beta-Kappa +nakagami Nakagami +ncx2 Non-central chi-squared +ncf Non-central F +t Student's T +nct Non-central Student's T +pareto Pareto +powerlaw Power-function +powerlognorm Power log normal +powernorm Power normal +rdist R distribution +reciprocal Reciprocal +rayleigh Rayleigh +rice Rice +recipinvgauss Reciprocal Inverse Gaussian +semicircular Semicircular +triang Triangular +truncexpon Truncated Exponential +truncnorm Truncated Normal +tukeylambda Tukey-Lambda +uniform Uniform +von_mises Von-Mises (Circular) +wald Wald +weibull_min Minimum Weibull (see Frechet) +weibull_max Maximum Weibull (see Frechet) +wrapcauchy Wrapped Cauchy +ksone Kolmogorov-Smirnov one-sided (no stats) +kstwobign Kolmogorov-Smirnov two-sided test for Large N (no stats) +=============== ============================================================== -DISCRETE (Total == 10 distributions) -============ -binom -- Binomial -bernoulli -- Bernoulli -nbinom -- Negative Binomial -geom -- Geometric -hypergeom -- Hypergeometric -logser -- Logarithmic (Log-Series, Series) -poisson -- Poisson -planck -- Planck (Discrete Exponential) -boltzmann -- Boltzmann (Truncated Discrete Exponential) -randint -- Discrete Uniform -zipf -- Zipf -dlaplace -- Discrete Laplacian +=============== ============================================================== +Discrete (Total == 10 distributions) +============================================================================== +binom Binomial +bernoulli Bernoulli +nbinom Negative Binomial +geom Geometric +hypergeom Hypergeometric +logser Logarithmic (Log-Series, Series) +poisson Poisson +planck Planck (Discrete Exponential) +boltzmann Boltzmann (Truncated Discrete Exponential) +randint Discrete Uniform +zipf Zipf +dlaplace Discrete Laplacian +=============== ============================================================== Statistical Functions (adapted from Gary Strangman) +----------------------------------------------------- -gmean -- _ -hmean -- _ -mean -- _ -cmedian -- _ -median -- _ -mode -- _ -tmean -- _ -tvar -- _ -tmin -- _ -tmax -- _ -tstd -- _ -tsem -- _ -moment -- _ -variation -- _ -skew -- _ -kurtosis -- _ -describe -- _ -skewtest -- _ -kurtosistest -- _ -normaltest -- _ +================= ============================================================== +gmean Geometric mean +hmean Harmonic mean +mean Arithmetic mean +cmedian Computed median +median Median +mode Modal value +tmean Truncated arithmetic mean +tvar Truncated variance +tmin _ +tmax _ +tstd _ +tsem _ +moment Central moment +variation Coefficient of variation +skew Skewness +kurtosis Fisher or Pearson kurtosis +describe Descriptive statistics +skewtest _ +kurtosistest _ +normaltest _ +================= ============================================================== -itemfreq -- _ -scoreatpercentile -- _ -percentileofscore -- _ -histogram2 -- _ -histogram -- _ -cumfreq -- _ -relfreq -- _ +================= ============================================================== +itemfreq _ +scoreatpercentile _ +percentileofscore _ +histogram2 _ +histogram _ +cumfreq _ +relfreq _ +================= ============================================================== -obrientransform -- _ -samplevar -- _ -samplestd -- _ -signaltonoise -- _ -bayes_mvs -- _ -var -- _ -std -- _ -stderr -- _ -sem -- _ -z -- _ -zs -- _ -zmap -- _ +================= ============================================================== +obrientransform _ +samplevar _ +samplestd _ +signaltonoise _ +bayes_mvs _ +var _ +std _ +stderr _ +sem _ +z _ +zs _ +zmap _ +================= ============================================================== -threshold -- _ -trimboth -- _ -trim1 -- _ -cov -- _ -corrcoef -- _ +================= ============================================================== +threshold _ +trimboth _ +trim1 _ +cov _ +corrcoef _ +================= ============================================================== -f_oneway -- _ -paired -- _ -pearsonr -- _ -spearmanr -- _ -pointbiserialr -- _ -kendalltau -- _ -linregress -- _ +================= ============================================================== +f_oneway _ +paired _ +pearsonr _ +spearmanr _ +pointbiserialr _ +kendalltau _ +linregress _ +================= ============================================================== -ttest_1samp -- _ -ttest_ind -- _ -ttest_rel -- _ -kstest -- _ -chisquare -- _ -ks_2samp -- _ -meanwhitneyu -- _ -tiecorrect -- _ -ranksums -- _ -wilcoxon -- _ -kruskal -- _ -friedmanchisquare -- _ +================= ============================================================== +ttest_1samp _ +ttest_ind _ +ttest_rel _ +kstest _ +chisquare _ +ks_2samp _ +meanwhitneyu _ +tiecorrect _ +ranksums _ +wilcoxon _ +kruskal _ +friedmanchisquare _ +================= ============================================================== -ansari -- _ -bartlett -- _ -levene -- _ -shapiro -- _ -anderson -- _ -binom_test -- _ -fligner -- _ -mood -- _ -oneway -- _ +================= ============================================================== +ansari _ +bartlett _ +levene _ +shapiro _ +anderson _ +binom_test _ +fligner _ +mood _ +oneway _ +================= ============================================================== +================= ============================================================== +glm _ +anova _ +================= ============================================================== -glm -- _ -anova -- _ +================= ============================================================== Plot-tests +================================================================================ +probplot _ +ppcc_max _ +ppcc_plot _ +================= ============================================================== -probplot -- _ -ppcc_max -- _ -ppcc_plot -- _ - For many more stat related functions install the software R and the interface package rpy. + """ postpone_import = 1 Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-30 19:08:36 UTC (rev 5301) +++ trunk/scipy/stats/stats.py 2008-12-30 23:30:23 UTC (rev 5302) @@ -2136,7 +2136,8 @@ #import scipy.stats #import distributions def kstest(rvs, cdf, args=(), N=20, alternative = 'two_sided', mode='approx',**kwds): - """Return the D-value and the p-value for a Kolmogorov-Smirnov test + """ + Return the D-value and the p-value for a Kolmogorov-Smirnov test This performs a test of the distribution G(x) of an observed random variable against a given distribution F(x). Under the null @@ -2151,14 +2152,12 @@ array: 1-D observations of random variables - callable: function to generate random variables, - requires keyword argument `size` + callable: function to generate random variables, requires keyword + argument `size` cdf : string or callable - string: name of a distribution in scipy.stats - if rvs is a string then cdf can evaluate to False - or be the same as rvs - + string: name of a distribution in scipy.stats, if rvs is a string then + cdf can evaluate to `False` or be the same as rvs callable: function to evaluate cdf args : tuple, sequence @@ -2167,6 +2166,7 @@ sample size if rvs is string or callable alternative : 'two_sided' (default), 'less' or 'greater' defines the alternative hypothesis (see explanation) + mode : 'approx' (default) or 'asymp' defines the distribution used for calculating p-value @@ -2205,8 +2205,7 @@ >>> kstest(x,'norm') (0.44435602715924361, 0.038850142705171065) - >>> #fix random seed to get the same result - >>> np.random.seed(987654321) + >>> np.random.seed(987654321) # set random seed to get the same result >>> kstest('norm','',N=100) (0.058352892479417884, 0.88531190944151261) @@ -2216,22 +2215,28 @@ >>> kstest(stats.norm.rvs(size=100),'norm') (0.058352892479417884, 0.88531190944151261) - **test against one-sided alternative hypothesis** + Test against one-sided alternative hypothesis: >>> np.random.seed(987654321) - >>> #shift distribution to larger values, so that cdf_dgp(x)< norm.cdf(x) - >>> x = stats.norm.rvs(loc=0.2, size=100) - >>> kstest(x,'norm', alternative = 'less') + + Shift distribution to larger values, so that cdf_dgp(x)< norm.cdf(x): + + >>> x = stats.norm.rvs(loc=0.2, size=100) + >>> kstest(x,'norm', alternative = 'less') (0.12464329735846891, 0.040989164077641749) - >>> #reject equal distribution against alternative hypothesis: less + + Reject equal distribution against alternative hypothesis: less + >>> kstest(x,'norm', alternative = 'greater') (0.0072115233216311081, 0.98531158590396395) - >>> #don't reject equal distribution against alternative hypothesis: greater + + Don't reject equal distribution against alternative hypothesis: greater + >>> kstest(x,'norm', mode='asymp') (0.12464329735846891, 0.08944488871182088) - **testing t distributed random variables against normal distribution** + Testing t distributed random variables against normal distribution: With 100 degrees of freedom the t distribution looks close to the normal distribution, and the kstest does not reject the hypothesis that the sample From scipy-svn at scipy.org Tue Dec 30 18:54:54 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 17:54:54 -0600 (CST) Subject: [Scipy-svn] r5303 - trunk/scipy/io/matlab Message-ID: <20081230235454.E2C40C7C00B@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-30 17:54:50 -0600 (Tue, 30 Dec 2008) New Revision: 5303 Added: trunk/scipy/io/matlab/gzipstreams.py Modified: trunk/scipy/io/matlab/mio5.py trunk/scipy/io/matlab/miobase.py Log: Fixed bug reading empty strings; added theoretically more satisfying as-needed gzip stream reader for compressed arrays Added: trunk/scipy/io/matlab/gzipstreams.py =================================================================== --- trunk/scipy/io/matlab/gzipstreams.py 2008-12-30 23:30:23 UTC (rev 5302) +++ trunk/scipy/io/matlab/gzipstreams.py 2008-12-30 23:54:50 UTC (rev 5303) @@ -0,0 +1,220 @@ +''' Object for reading from gzipped file-like object + +Edited by Matthew Brett, with thanks, from +http://effbot.org/librarybook/zlib-example-4.py + +The copyright and license for that code is: + +Copyright 1995-2008 by Fredrik Lundh + +By obtaining, using, and/or copying this software and/or its +associated documentation, you agree that you have read, understood, +and will comply with the following terms and conditions: + +Permission to use, copy, modify, and distribute this software and its +associated documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies, and that both that copyright notice and this permission notice +appear in supporting documentation, and that the name of Secret Labs +AB or the author not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR +ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +from zlib import decompressobj + + +class GzipInputStream(object): + ''' Fileobject to wrap zlib compressed stream for reading + + >>> from StringIO import StringIO + >>> from zlib import compress + >>> S = 'A handy module for reading compressed streams' + >>> F = StringIO(compress(S)) + >>> ZF = GzipInputStream(F) + >>> ZF.read() + 'A handy module for reading compressed streams' + >>> ZF.tell() == len(S) + True + >>> F = StringIO(compress(S)) + >>> ZF = GzipInputStream(F) + >>> ZF.tell() + 0 + >>> ZF.read(6) + 'A hand' + >>> ZF.tell() + 6 + >>> F = StringIO(compress(S)) + >>> ZF = GzipInputStream(F, 6) # with length + >>> ZF.read() + 'A hand' + >>> ZF.read() + '' + >>> ZF.tell() + 6 + >>> + ''' + + blocksize = 16384 # 16K + def __init__(self, fileobj, length=None): + ''' Initialize GzipInputStream + + Parameters + ---------- + fileobj : file-like object + Object only need implement ``read`` method + length : None or int, optional + Uncompressed length of input stream in bytes + ''' + self.fileobj = fileobj + self.length=length + self.exhausted = False + self.unzipped_pos = 0 + self.data = "" + self._unzipper = decompressobj() + self._bytes_read = 0 + + def __fill(self, bytes): + ''' Fill self.data with at least *bytes* number of bytes + If bytes == -1, continue until the end of the stream + + Returns ``None`` + ''' + if self.exhausted: + return + # read until we have enough bytes in the buffer + read_to_end = bytes == -1 + n_to_fetch = self.blocksize + while read_to_end or len(self.data) < bytes: + if self.length: # do not read beyond specified length + n_to_fetch = min(self.length-self._bytes_read, + self.blocksize) + if n_to_fetch == 0: + self.exhausted = True + break + data = self.fileobj.read(n_to_fetch) + if data: + self.__add_data(self._unzipper.decompress(data)) + if len(data) < n_to_fetch: # hit end of file + self.__add_data(self._unzipper.flush()) + self.exhausted = True + break + + def __add_data(self, data): + self.data += data + self._bytes_read += len(data) + + def seek(self, offset, whence=0): + ''' Set position in uncompressed stream + + Parameters + ---------- + offset : int + byte offset relative to position given by *whence* + offsets are in terms of uncompressed bytes from stream + whence : {0,1} + 0 signifies *offset* is relative to beginning of file + 1 means *offset* is relative to current position + + Returns + ------- + None + ''' + if whence == 0: + position = offset + elif whence == 1: + position = self.unzipped_pos + offset + else: + raise IOError, "Illegal argument" + if position < self.unzipped_pos: + raise IOError, "Cannot seek backwards" + + # skip forward, in blocks + while position > self.unzipped_pos: + if not self.read(min(position - self.unzipped_pos, + self.blocksize)): + break + + def tell(self): + ''' Return current position in terms of uncompressed bytes ''' + return self.unzipped_pos + + def read(self, bytes = -1): + ''' Read bytes from file + + Parameters + ---------- + bytes : int, optional + If *bytes* is a positive integer, read this many bytes + from file. If *bytes* == -1 (the default), read all bytes + to the end of file, where the end of the file is detected + by running out of read data, or by the ``length`` + attribute. + + Returns + ------- + data : string + string containing read data + + ''' + self.__fill(bytes) + if bytes == -1: + data = self.data + self.data = "" + else: + data = self.data[:bytes] + self.data = self.data[bytes:] + self.unzipped_pos += len(data) + return data + + def readline(self): + ''' Read text line from data + + Examples + -------- + >>> from StringIO import StringIO + >>> from zlib import compress + >>> S = 'A handy module\\nfor reading\\ncompressed streams' + >>> F = StringIO(compress(S)) + >>> ZF = GzipInputStream(F) + >>> ZF.readline() + 'A handy module\\n' + >>> ZF.readline() + 'for reading\\n' + ''' + # make sure we have an entire line + while not self.exhausted and "\n" not in self.data: + self.__fill(len(self.data) + 512) + i = self.data.find("\n") + 1 + if i <= 0: + return self.read() + return self.read(i) + + def readlines(self): + ''' Read all data broken up into list of text lines + >>> from StringIO import StringIO + >>> from zlib import compress + >>> S = 'A handy module\\nfor reading\\ncompressed streams' + >>> F = StringIO(compress(S)) + >>> ZF = GzipInputStream(F) + >>> ZF.readlines() + ['A handy module\\n', 'for reading\\n', 'compressed streams'] + >>> + ''' + lines = [] + while 1: + s = self.readline() + if not s: + break + lines.append(s) + return lines + Modified: trunk/scipy/io/matlab/mio5.py =================================================================== --- trunk/scipy/io/matlab/mio5.py 2008-12-30 23:30:23 UTC (rev 5302) +++ trunk/scipy/io/matlab/mio5.py 2008-12-30 23:54:50 UTC (rev 5303) @@ -12,6 +12,7 @@ import sys import zlib +from gzipstreams import GzipInputStream from StringIO import StringIO from copy import copy as pycopy import warnings @@ -322,14 +323,12 @@ class Mat5ZArrayReader(Mat5ArrayReader): ''' Getter for compressed arrays - Reads and uncompresses gzipped stream on init, providing wrapper + Sets up reader for gzipped stream on init, providing wrapper for this new sub-stream. ''' def __init__(self, array_reader, byte_count): - '''Reads and uncompresses gzipped stream''' - data = array_reader.mat_stream.read(byte_count) super(Mat5ZArrayReader, self).__init__( - StringIO(zlib.decompress(data)), + GzipInputStream(array_reader.mat_stream, byte_count), array_reader.dtypes, array_reader.processor_func, array_reader.codecs, Modified: trunk/scipy/io/matlab/miobase.py =================================================================== --- trunk/scipy/io/matlab/miobase.py 2008-12-30 23:30:23 UTC (rev 5302) +++ trunk/scipy/io/matlab/miobase.py 2008-12-30 23:54:50 UTC (rev 5303) @@ -308,12 +308,13 @@ # Convert char array to string or array of strings dims = arr.shape if len(dims) >= 2: # return array of strings - dtt = self.order_code + 'U' n_dims = dims[:-1] + last_dim = dims[-1] str_arr = arr.reshape( (small_product(n_dims), - dims[-1])) - arr = np.empty(n_dims, dtype='U%d' % dims[-1]) + last_dim)) + dtstr = 'U%d' % (last_dim and last_dim or 1) + arr = np.empty(n_dims, dtype=dtstr) for i in range(0, n_dims[-1]): arr[...,i] = self.chars_to_str(str_arr[i]) else: # return string From scipy-svn at scipy.org Tue Dec 30 19:11:46 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 18:11:46 -0600 (CST) Subject: [Scipy-svn] r5304 - trunk/scipy/stats Message-ID: <20081231001146.BF9D4C7C00B@scipy.org> Author: ptvirtan Date: 2008-12-30 18:11:29 -0600 (Tue, 30 Dec 2008) New Revision: 5304 Modified: trunk/scipy/stats/distributions.py Log: Fix scipy.stats distribution extradoc indentation levels Modified: trunk/scipy/stats/distributions.py =================================================================== --- trunk/scipy/stats/distributions.py 2008-12-30 23:54:50 UTC (rev 5303) +++ trunk/scipy/stats/distributions.py 2008-12-31 00:11:29 UTC (rev 5304) @@ -25,6 +25,7 @@ from scipy.special import gammaln as gamln from copy import copy import vonmises_cython +import textwrap __all__ = [ 'rv_continuous', @@ -394,6 +395,7 @@ Examples -------- + >>> import matplotlib.pyplot as plt >>> numargs = generic.numargs >>> [ ] = [0.9,]*numargs @@ -469,6 +471,7 @@ if self.__doc__ is None: self.__doc__ = rv_continuous.__doc__ if self.__doc__ is not None: + self.__doc__ = textwrap.dedent(self.__doc__) if longname is not None: self.__doc__ = self.__doc__.replace("A Generic",longname) if name is not None: @@ -478,7 +481,7 @@ else: self.__doc__ = self.__doc__.replace("",shapes) if extradoc is not None: - self.__doc__ = self.__doc__ + extradoc + self.__doc__ += textwrap.dedent(extradoc) def _ppf_to_solve(self, x, q,*args): return apply(self.cdf, (x, )+args)-q @@ -3666,29 +3669,34 @@ keyword) a tuple of sequences (xk,pk) which describes only those values of X (xk) that occur with nonzero probability (pk). - Examples: - --------- - >>> import matplotlib.pyplot as plt - >>> numargs = generic.numargs - >>> [ ] = ['Replace with resonable value',]*numargs + Examples + -------- + >>> import matplotlib.pyplot as plt + >>> numargs = generic.numargs + >>> [ ] = ['Replace with resonable value',]*numargs + Display frozen pmf: - >>> rv = generic() - >>> x = np.arange(0,np.min(rv.dist.b,3)+1) - >>> h = plt.plot(x,rv.pmf(x)) + >>> rv = generic() + >>> x = np.arange(0,np.min(rv.dist.b,3)+1) + >>> h = plt.plot(x,rv.pmf(x)) + Check accuracy of cdf and ppf: - >>> prb = generic.cdf(x,) - >>> h = plt.semilogy(np.abs(x-generic.ppf(prb,))+1e-20) + >>> prb = generic.cdf(x,) + >>> h = plt.semilogy(np.abs(x-generic.ppf(prb,))+1e-20) + Random number generation: - >>> R = generic.rvs(,size=100) + >>> R = generic.rvs(,size=100) + Custom made discrete distribution: - >>> vals = [arange(7),(0.1,0.2,0.3,0.1,0.1,0.1,0.1)] - >>> custm = rv_discrete(name='custm',values=vals) - >>> h = plt.plot(vals[0],custm.pmf(vals[0])) + >>> vals = [arange(7),(0.1,0.2,0.3,0.1,0.1,0.1,0.1)] + >>> custm = rv_discrete(name='custm',values=vals) + >>> h = plt.plot(vals[0],custm.pmf(vals[0])) + """ def __init__(self, a=0, b=inf, name=None, badvalue=None, moment_tol=1e-8,values=None,inc=1,longname=None, @@ -3768,6 +3776,7 @@ if self.__doc__ is None: self.__doc__ = rv_discrete.__doc__ if self.__doc__ is not None: + self.__doc__ = textwrap.dedent(self.__doc__) self.__doc__ = self.__doc__.replace("A Generic",longname) if name is not None: self.__doc__ = self.__doc__.replace("generic",name) @@ -3778,7 +3787,7 @@ ind = self.__doc__.find("You can construct an arbitrary") self.__doc__ = self.__doc__[:ind].strip() if extradoc is not None: - self.__doc__ = self.__doc__ + extradoc + self.__doc__ += textwrap.dedent(extradoc) def _rvs(self, *args): return self._ppf(mtrand.random_sample(self._size),*args) From scipy-svn at scipy.org Tue Dec 30 19:38:00 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Tue, 30 Dec 2008 18:38:00 -0600 (CST) Subject: [Scipy-svn] r5305 - trunk/doc/source Message-ID: <20081231003800.78677C7C00B@scipy.org> Author: ptvirtan Date: 2008-12-30 18:37:32 -0600 (Tue, 30 Dec 2008) New Revision: 5305 Modified: trunk/doc/source/stats.rst Log: Link stats.mstats.rst to documentation Modified: trunk/doc/source/stats.rst =================================================================== --- trunk/doc/source/stats.rst 2008-12-31 00:11:29 UTC (rev 5304) +++ trunk/doc/source/stats.rst 2008-12-31 00:37:32 UTC (rev 5305) @@ -33,6 +33,14 @@ rv_discrete.isf rv_discrete.stats + +Masked statistics functions +=========================== + +.. toctree:: + + stats.mstats + Continuous distributions ======================== From scipy-svn at scipy.org Wed Dec 31 02:05:49 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 01:05:49 -0600 (CST) Subject: [Scipy-svn] r5306 - trunk/doc/release Message-ID: <20081231070549.33D19C7C00B@scipy.org> Author: jarrod.millman Date: 2008-12-31 01:02:20 -0600 (Wed, 31 Dec 2008) New Revision: 5306 Modified: trunk/doc/release/0.7.0-notes.rst Log: minor fixes to release notes Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-31 00:37:32 UTC (rev 5305) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-31 07:02:20 UTC (rev 5306) @@ -249,12 +249,22 @@ For more information, please see `The NumPy/SciPy Testing Guide `__. +We have also greatly improved our test coverage. There were just over 2,000 unit tests in +the 0.6.0 release; this release nearly doubles that number with just under 4,000 unit tests. + Building SciPy -------------- Support for NumScons has been added. NumScons is a tentative new -build system for NumPy/SciPy, using scons at its core. +build system for NumPy/SciPy, using `SCons `__ at its core. +SCons is a next-generation build system meant to replace the venerable ``Make`` with +the integrated functionality of ``autoconf``/``automake`` and ``ccache``. Scons is +written in Python and its configuration files are Python scripts. NumScons is meant +to replace NumPy's custom version of ``distutils`` providing more advanced functionality +such as autoconf, improved fortran support, more tools, and support for +``numpy.distutils``/``scons`` cooperation. + Sandbox Removed --------------- From scipy-svn at scipy.org Wed Dec 31 02:13:07 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 01:13:07 -0600 (CST) Subject: [Scipy-svn] r5307 - in trunk/scipy: io/matlab ndimage ndimage/tests signal/tests stats stats/tests Message-ID: <20081231071307.B71EAC7C00B@scipy.org> Author: jarrod.millman Date: 2008-12-31 01:13:05 -0600 (Wed, 31 Dec 2008) New Revision: 5307 Modified: trunk/scipy/io/matlab/gzipstreams.py trunk/scipy/io/matlab/mio5.py trunk/scipy/ndimage/doccer.py trunk/scipy/ndimage/filters.py trunk/scipy/ndimage/tests/test_doccer.py trunk/scipy/signal/tests/test_signaltools.py trunk/scipy/stats/stats.py trunk/scipy/stats/tests/test_stats.py Log: ran reindent Modified: trunk/scipy/io/matlab/gzipstreams.py =================================================================== --- trunk/scipy/io/matlab/gzipstreams.py 2008-12-31 07:02:20 UTC (rev 5306) +++ trunk/scipy/io/matlab/gzipstreams.py 2008-12-31 07:13:05 UTC (rev 5307) @@ -61,9 +61,9 @@ '' >>> ZF.tell() 6 - >>> + >>> ''' - + blocksize = 16384 # 16K def __init__(self, fileobj, length=None): ''' Initialize GzipInputStream @@ -164,7 +164,7 @@ ------- data : string string containing read data - + ''' self.__fill(bytes) if bytes == -1: @@ -217,4 +217,3 @@ break lines.append(s) return lines - Modified: trunk/scipy/io/matlab/mio5.py =================================================================== --- trunk/scipy/io/matlab/mio5.py 2008-12-31 07:02:20 UTC (rev 5306) +++ trunk/scipy/io/matlab/mio5.py 2008-12-31 07:13:05 UTC (rev 5307) @@ -799,7 +799,7 @@ def write(self): self.write_header() self._write_items() - + def _write_items(self): # loop over data, column major A = np.atleast_2d(self.arr).flatten('F') @@ -893,11 +893,11 @@ # No interesting conversion possible raise TypeError('Could not convert %s (type %s) to array' % (arr, type(arr))) - args = (self.stream, - narr, - name, - is_global, - self.unicode_strings, + args = (self.stream, + narr, + name, + is_global, + self.unicode_strings, self.long_field_names) if isinstance(narr, MatlabFunction): return Mat5FunctionWriter(*args) Modified: trunk/scipy/ndimage/doccer.py =================================================================== --- trunk/scipy/ndimage/doccer.py 2008-12-31 07:02:20 UTC (rev 5306) +++ trunk/scipy/ndimage/doccer.py 2008-12-31 07:13:05 UTC (rev 5307) @@ -94,7 +94,7 @@ unindent_params : {False, True}, boolean, optional If True, strip common indentation from all parameters in docdict - + Returns ------- decfunc : function Modified: trunk/scipy/ndimage/filters.py =================================================================== --- trunk/scipy/ndimage/filters.py 2008-12-31 07:02:20 UTC (rev 5306) +++ trunk/scipy/ndimage/filters.py 2008-12-31 07:13:05 UTC (rev 5307) @@ -89,7 +89,7 @@ 'extra_arguments':_extra_arguments_doc, 'extra_keywords':_extra_keywords_doc, } - + docfiller = doccer.filldoc(docdict) @docfiller @@ -99,7 +99,7 @@ The lines of the array along the given axis are correlated with the given weights. - + Parameters ---------- %(input)s @@ -921,7 +921,7 @@ %(cval)s %(origin)s %(extra_arguments)s - %(extra_keywords)s + %(extra_keywords)s """ if extra_keywords is None: extra_keywords = {} @@ -962,7 +962,7 @@ %(cval)s %(origin)s %(extra_arguments)s - %(extra_keywords)s + %(extra_keywords)s """ if extra_keywords is None: extra_keywords = {} Modified: trunk/scipy/ndimage/tests/test_doccer.py =================================================================== --- trunk/scipy/ndimage/tests/test_doccer.py 2008-12-31 07:02:20 UTC (rev 5306) +++ trunk/scipy/ndimage/tests/test_doccer.py 2008-12-31 07:13:05 UTC (rev 5307) @@ -62,8 +62,8 @@ # affect subsequent indent of inserted parameter yield assert_equal, formatted, """Single line doc Another test with some indent""" - + def test_decorator(): # with unindentation of parameters decorator = sndd.filldoc(doc_dict, True) Modified: trunk/scipy/signal/tests/test_signaltools.py =================================================================== --- trunk/scipy/signal/tests/test_signaltools.py 2008-12-31 07:02:20 UTC (rev 5306) +++ trunk/scipy/signal/tests/test_signaltools.py 2008-12-31 07:13:05 UTC (rev 5307) @@ -38,7 +38,7 @@ [ 3, 33, 53, 67, 1, 78, 74, 55, 12, 83], [ 7, 11, 46, 70, 60, 47, 24, 43, 61, 26], [32, 61, 88, 7, 39, 4, 92, 64, 45, 61]] - + d = signal.medfilt(f, [7, 3]) e = signal.medfilt2d(np.array(f, np.float), [7, 3]) assert_array_equal(d, [[ 0, 50, 50, 50, 42, 15, 15, 18, 27, 0], Modified: trunk/scipy/stats/stats.py =================================================================== --- trunk/scipy/stats/stats.py 2008-12-31 07:02:20 UTC (rev 5306) +++ trunk/scipy/stats/stats.py 2008-12-31 07:13:05 UTC (rev 5307) @@ -1904,7 +1904,7 @@ >>> from scipy import stats >>> import numpy as np - + >>> #fix seed to get the same result >>> np.random.seed(7654567) >>> rvs = stats.norm.rvs(loc=5,scale=10,size=(50,2)) @@ -1938,14 +1938,14 @@ d = np.mean(a,axis) - popmean v = np.var(a, axis, ddof=1) - + t = d / np.sqrt(v/float(n)) t = np.where((d==0)*(v==0), 1.0, t) #define t=0/0 = 1, identical mean, var prob = distributions.t.sf(np.abs(t),df)*2 #use np.abs to get upper tail #distributions.t.sf currently does not propagate nans #this can be dropped, if distributions.t.sf propagates nans #if this is removed, then prob = prob[()] needs to be removed - prob = np.where(np.isnan(t), np.nan, prob) + prob = np.where(np.isnan(t), np.nan, prob) if t.ndim == 0: t = t[()] @@ -2004,7 +2004,7 @@ >>> np.random.seed(12345678) test with sample with identical means - + >>> rvs1 = stats.norm.rvs(loc=5,scale=10,size=500) >>> rvs2 = stats.norm.rvs(loc=5,scale=10,size=500) >>> stats.ttest_ind(rvs1,rvs2) @@ -2012,7 +2012,7 @@ test with sample with different means - + >>> rvs3 = stats.norm.rvs(loc=8,scale=10,size=500) >>> stats.ttest_ind(rvs1,rvs3) (-5.0434013458585092, 5.4302979468623391e-007) @@ -2032,7 +2032,7 @@ t = d/np.sqrt(svar*(1.0/n1 + 1.0/n2)) t = np.where((d==0)*(svar==0), 1.0, t) #define t=0/0 = 0, identical means prob = distributions.t.sf(np.abs(t),df)*2#use np.abs to get upper tail - + #distributions.t.sf currently does not propagate nans #this can be dropped, if distributions.t.sf propagates nans #if this is removed, then prob = prob[()] needs to be removed @@ -2041,7 +2041,7 @@ if t.ndim == 0: t = t[()] prob = prob[()] - + return t, prob @@ -2113,15 +2113,15 @@ d = (a-b).astype('d') v = np.var(d,axis,ddof=1) dm = np.mean(d, axis) - + t = dm / np.sqrt(v/float(n)) - t = np.where((dm==0)*(v==0), 1.0, t) #define t=0/0 = 1, zero mean and var + t = np.where((dm==0)*(v==0), 1.0, t) #define t=0/0 = 1, zero mean and var prob = distributions.t.sf(np.abs(t),df)*2 #use np.abs to get upper tail #distributions.t.sf currently does not propagate nans #this can be dropped, if distributions.t.sf propagates nans #if this is removed, then prob = prob[()] needs to be removed prob = np.where(np.isnan(t), np.nan, prob) - + ## if not np.isscalar(t): ## probs = np.reshape(probs, t.shape) # this should be redundant ## if not np.isscalar(prob) and len(prob) == 1: Modified: trunk/scipy/stats/tests/test_stats.py =================================================================== --- trunk/scipy/stats/tests/test_stats.py 2008-12-31 07:02:20 UTC (rev 5306) +++ trunk/scipy/stats/tests/test_stats.py 2008-12-31 07:13:05 UTC (rev 5307) @@ -1088,18 +1088,18 @@ t,p = stats.ttest_rel([0,0,0],[1,1,1]) assert_equal((np.abs(t),p), (np.inf, 0)) assert_equal(stats.ttest_rel([0,0,0], [0,0,0]), (1.0, 0.42264973081037427)) - + #check that nan in input array result in nan output anan = np.array([[1,np.nan],[-1,1]]) assert_equal(stats.ttest_ind(anan, np.zeros((2,2))),([0, np.nan], [1,np.nan])) - - + + def test_ttest_ind(): #regression test tr = 1.0912746897927283 pr = 0.27647818616351882 tpr = ([tr,-tr],[pr,pr]) - + rvs2 = np.linspace(1,100,100) rvs1 = np.linspace(5,105,100) rvs1_2D = np.array([rvs1, rvs2]) @@ -1133,15 +1133,15 @@ #check that nan in input array result in nan output anan = np.array([[1,np.nan],[-1,1]]) assert_equal(stats.ttest_ind(anan, np.zeros((2,2))),([0, np.nan], [1,np.nan])) - - + + def test_ttest_1samp_new(): n1, n2, n3 = (10,15,20) rvn1 = stats.norm.rvs(loc=5,scale=10,size=(n1,n2,n3)) rvn2 = stats.norm.rvs(loc=5,scale=10,size=(n1,n2,n3)) - + #check multidimensional array and correct axis handling #deterministic rvn1 and rvn2 would be better as in test_ttest_rel t1,p1 = stats.ttest_1samp(rvn1[:,:,:], np.ones((n2,n3)),axis=0) From scipy-svn at scipy.org Wed Dec 31 02:52:00 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 01:52:00 -0600 (CST) Subject: [Scipy-svn] r5308 - trunk/doc/release Message-ID: <20081231075200.1450DC7C00B@scipy.org> Author: jarrod.millman Date: 2008-12-31 01:51:58 -0600 (Wed, 31 Dec 2008) New Revision: 5308 Modified: trunk/doc/release/0.7.0-notes.rst Log: added details about improved documentation Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-31 07:13:05 UTC (rev 5307) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-31 07:51:58 UTC (rev 5308) @@ -184,11 +184,17 @@ Major documentation improvements -------------------------------- -Scipy documentation is now more accessible than previously; you can -view a HTML reference manual online at http://docs.scipy.org/ or -download it as a PDF file. An updated tutorial is also available, and -it shows how to use several essential parts of Scipy. +SciPy documentation is greatly improved; you can +view a HTML reference manual `online `__ or +download it as a PDF file. The new reference guide was built using +the popular `Sphinx tool `__. +This release also includes an updated tutorial, which hadn't been +available since SciPy was ported to NumPy in 2005. While not +comprehensive, the tutorial shows how to use several essential +parts of Scipy. It also includes the ``ndimage`` documentation +from the ``numarray`` manual. + Nevertheless, more effort is still needed on the documentation front. Luckily, contributing to Scipy documentation is now easier than before: if you find that a part of it requires improvements, and want From scipy-svn at scipy.org Wed Dec 31 06:13:40 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 05:13:40 -0600 (CST) Subject: [Scipy-svn] r5309 - trunk/scipy/io/matlab Message-ID: <20081231111340.AFD8AC7C015@scipy.org> Author: matthew.brett at gmail.com Date: 2008-12-31 05:13:37 -0600 (Wed, 31 Dec 2008) New Revision: 5309 Modified: trunk/scipy/io/matlab/gzipstreams.py Log: Fixed brain error in calculation of zip stream length Modified: trunk/scipy/io/matlab/gzipstreams.py =================================================================== --- trunk/scipy/io/matlab/gzipstreams.py 2008-12-31 07:51:58 UTC (rev 5308) +++ trunk/scipy/io/matlab/gzipstreams.py 2008-12-31 11:13:37 UTC (rev 5309) @@ -53,30 +53,21 @@ 'A hand' >>> ZF.tell() 6 - >>> F = StringIO(compress(S)) - >>> ZF = GzipInputStream(F, 6) # with length - >>> ZF.read() - 'A hand' - >>> ZF.read() - '' - >>> ZF.tell() - 6 - >>> ''' blocksize = 16384 # 16K - def __init__(self, fileobj, length=None): + def __init__(self, fileobj, zipped_length=None): ''' Initialize GzipInputStream Parameters ---------- fileobj : file-like object Object only need implement ``read`` method - length : None or int, optional - Uncompressed length of input stream in bytes + zipped_length : None or int, optional + Compressed length of input stream in bytes ''' self.fileobj = fileobj - self.length=length + self.zipped_length=zipped_length self.exhausted = False self.unzipped_pos = 0 self.data = "" @@ -95,24 +86,21 @@ read_to_end = bytes == -1 n_to_fetch = self.blocksize while read_to_end or len(self.data) < bytes: - if self.length: # do not read beyond specified length - n_to_fetch = min(self.length-self._bytes_read, + if self.zipped_length: # do not read beyond specified length + n_to_fetch = min(self.zipped_length-self._bytes_read, self.blocksize) if n_to_fetch == 0: self.exhausted = True break data = self.fileobj.read(n_to_fetch) + self._bytes_read += len(data) if data: - self.__add_data(self._unzipper.decompress(data)) + self.data += self._unzipper.decompress(data) if len(data) < n_to_fetch: # hit end of file - self.__add_data(self._unzipper.flush()) + self.data += self._unzipper.flush() self.exhausted = True break - def __add_data(self, data): - self.data += data - self._bytes_read += len(data) - def seek(self, offset, whence=0): ''' Set position in uncompressed stream @@ -157,7 +145,7 @@ If *bytes* is a positive integer, read this many bytes from file. If *bytes* == -1 (the default), read all bytes to the end of file, where the end of the file is detected - by running out of read data, or by the ``length`` + by running out of read data, or by the ``zipped_length`` attribute. Returns From scipy-svn at scipy.org Wed Dec 31 15:37:17 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 14:37:17 -0600 (CST) Subject: [Scipy-svn] r5310 - trunk/scipy/ndimage/tests Message-ID: <20081231203717.606B8C7C015@scipy.org> Author: alan.mcintyre Date: 2008-12-31 14:36:21 -0600 (Wed, 31 Dec 2008) New Revision: 5310 Modified: trunk/scipy/ndimage/tests/test_regression.py Log: Use run_module_suite instead of deprecated NumpyTest. Modified: trunk/scipy/ndimage/tests/test_regression.py =================================================================== --- trunk/scipy/ndimage/tests/test_regression.py 2008-12-31 11:13:37 UTC (rev 5309) +++ trunk/scipy/ndimage/tests/test_regression.py 2008-12-31 20:36:21 UTC (rev 5310) @@ -17,4 +17,4 @@ ndimage.zoom(x, 2, output=np.zeros((6,8))) if __name__ == "__main__": - NumpyTest().run() + run_module_suite() From scipy-svn at scipy.org Wed Dec 31 17:06:02 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 16:06:02 -0600 (CST) Subject: [Scipy-svn] r5311 - trunk/doc/release Message-ID: <20081231220602.4EA95C8410C@scipy.org> Author: jarrod.millman Date: 2008-12-31 16:06:00 -0600 (Wed, 31 Dec 2008) New Revision: 5311 Modified: trunk/doc/release/0.7.0-notes.rst Log: add blurb about deprecated io functions Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-31 20:36:21 UTC (rev 5310) +++ trunk/doc/release/0.7.0-notes.rst 2008-12-31 22:06:00 UTC (rev 5311) @@ -75,7 +75,14 @@ NumPy 1.1.0 and will take place over many release. SciPy 0.7.0 has several changes including: -* many of the functions in scipy.io have been deprecated +* Several functions in ``scipy.io`` have been deprecated and will be removed + in the 0.8.0 release including ``npfile``, ``save``, ``load``, ``create_module``, + ``create_shelf``, ``objload``, ``objsave``, ``fopen``, ``read_array``, + ``write_array``, ``fread``, ``fwrite``, ``bswap``, ``packbits``, ``unpackbits``, + and ``convert_objectarray``. Some of these functions have been replaced by + NumPy's raw reading and writing capabilities, memory-mapping capabilities, + or array methods. Others have been moved from SciPy to NumPy, since basic + array reading and writing capability is now handled by NumPy. * the Matlab (TM) file readers/writers have a number of improvements: * default version 5 From scipy-svn at scipy.org Wed Dec 31 17:16:37 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 16:16:37 -0600 (CST) Subject: [Scipy-svn] r5312 - in trunk/scipy: io/matlab stats/tests Message-ID: <20081231221637.E35D0C8410C@scipy.org> Author: jarrod.millman Date: 2008-12-31 16:16:36 -0600 (Wed, 31 Dec 2008) New Revision: 5312 Modified: trunk/scipy/io/matlab/mio5.py trunk/scipy/stats/tests/test_discrete_basic.py Log: identity test faster than equality test Modified: trunk/scipy/io/matlab/mio5.py =================================================================== --- trunk/scipy/io/matlab/mio5.py 2008-12-31 22:06:00 UTC (rev 5311) +++ trunk/scipy/io/matlab/mio5.py 2008-12-31 22:16:36 UTC (rev 5312) @@ -904,7 +904,7 @@ if isinstance(narr, MatlabObject): return Mat5ObjectWriter(*args) if narr.dtype.hasobject: # cell or struct array - if narr.dtype.fields == None: + if narr.dtype.fields is None: return Mat5CellWriter(*args) else: return Mat5StructWriter(*args) Modified: trunk/scipy/stats/tests/test_discrete_basic.py =================================================================== --- trunk/scipy/stats/tests/test_discrete_basic.py 2008-12-31 22:06:00 UTC (rev 5311) +++ trunk/scipy/stats/tests/test_discrete_basic.py 2008-12-31 22:16:36 UTC (rev 5312) @@ -28,7 +28,7 @@ def test_discrete_basic(): for distname, arg in distdiscrete: distfn = getattr(stats,distname) - #assert stats.dlaplace.rvs(0.8) != None + #assert stats.dlaplace.rvs(0.8) is not None np.random.seed(9765456) rvs = distfn.rvs(size=2000,*arg) m,v = distfn.stats(*arg) From scipy-svn at scipy.org Wed Dec 31 17:22:46 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 16:22:46 -0600 (CST) Subject: [Scipy-svn] r5313 - in trunk/scipy: io io/matlab sparse/linalg/dsolve/umfpack/tests Message-ID: <20081231222246.E6DA3C8410C@scipy.org> Author: jarrod.millman Date: 2008-12-31 16:22:45 -0600 (Wed, 31 Dec 2008) New Revision: 5313 Modified: trunk/scipy/io/matlab/mio.py trunk/scipy/io/mmio.py trunk/scipy/sparse/linalg/dsolve/umfpack/tests/try_umfpack.py Log: use string method over slicing Modified: trunk/scipy/io/matlab/mio.py =================================================================== --- trunk/scipy/io/matlab/mio.py 2008-12-31 22:16:36 UTC (rev 5312) +++ trunk/scipy/io/matlab/mio.py 2008-12-31 22:22:45 UTC (rev 5313) @@ -25,7 +25,7 @@ warnings.warn('Searching for mat files on python system path will be ' + 'removed in future versions of scipy', FutureWarning, stacklevel=2) - if appendmat and file_name[-4:] == ".mat": + if appendmat and file_name.endswith(".mat"): file_name = file_name[:-4] if os.sep in file_name: full_name = file_name Modified: trunk/scipy/io/mmio.py =================================================================== --- trunk/scipy/io/mmio.py 2008-12-31 22:16:36 UTC (rev 5312) +++ trunk/scipy/io/mmio.py 2008-12-31 22:22:45 UTC (rev 5313) @@ -208,10 +208,10 @@ elif os.path.isfile(filespec+'.mtx.bz2'): filespec = filespec + '.mtx.bz2' # open filename - if filespec[-3:] == '.gz': + if filespec.endswith('.gz'): import gzip stream = gzip.open(filespec, mode) - elif filespec[-4:] == '.bz2': + elif filespec.endswith('.bz2'): import bz2 stream = bz2.BZ2File(filespec, 'r') else: Modified: trunk/scipy/sparse/linalg/dsolve/umfpack/tests/try_umfpack.py =================================================================== --- trunk/scipy/sparse/linalg/dsolve/umfpack/tests/try_umfpack.py 2008-12-31 22:16:36 UTC (rev 5312) +++ trunk/scipy/sparse/linalg/dsolve/umfpack/tests/try_umfpack.py 2008-12-31 22:22:45 UTC (rev 5313) @@ -88,7 +88,7 @@ print 'format:', options.format print 'reading...' - if fileName[-3:] == '.gz': + if fileName.endswith('.gz'): fd = gzip.open( fileName ) else: fd = open( fileName ) From scipy-svn at scipy.org Wed Dec 31 19:32:12 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 18:32:12 -0600 (CST) Subject: [Scipy-svn] r5314 - trunk/doc/release Message-ID: <20090101003212.B9941C8410D@scipy.org> Author: jarrod.millman Date: 2008-12-31 18:32:11 -0600 (Wed, 31 Dec 2008) New Revision: 5314 Modified: trunk/doc/release/0.7.0-notes.rst Log: introduction to release notes Modified: trunk/doc/release/0.7.0-notes.rst =================================================================== --- trunk/doc/release/0.7.0-notes.rst 2008-12-31 22:22:45 UTC (rev 5313) +++ trunk/doc/release/0.7.0-notes.rst 2009-01-01 00:32:11 UTC (rev 5314) @@ -4,10 +4,24 @@ .. contents:: -This stable release comes almost one year after the 0.6.0 release +This new minor release comes almost one year after the 0.6.0 release and contains many new features, numerous bug-fixes, improved test -coverage, and better documentation. +coverage, and better documentation. There have been a number of +deprecations and API changes in this release, which are documented +below. While NumPy is an extremely stable, production-ready package, +SciPy is still under rapid development. Every effort is made to ensure +that our code is as stable and bug-free as possible (e.g., this release +almost doubles the number of unit tests compared to 0.6.0). However, as +we work toward the first stable, production-ready release (1.0.0), we +will be adding new modules and packages and we reserve the right to modify +SciPy's API and move code around to make the overall code organization +as intuitive as possible for new users. +All users are encouraged to upgrade to this release as there are a large +number of bug-fixes and optimizations. Moreover, our development attention +will now shift to bug-fix releases on the 0.7.x branch and new feature on +the development trunk. + Please note that unlike previous versions of SciPy, this release requires Python 2.4 or 2.5. This release also requires NumPy 1.2.0 or greater. From scipy-svn at scipy.org Wed Dec 31 20:12:36 2008 From: scipy-svn at scipy.org (scipy-svn at scipy.org) Date: Wed, 31 Dec 2008 19:12:36 -0600 (CST) Subject: [Scipy-svn] r5315 - trunk Message-ID: <20090101011236.C4592C8410D@scipy.org> Author: jarrod.millman Date: 2008-12-31 19:12:34 -0600 (Wed, 31 Dec 2008) New Revision: 5315 Removed: trunk/new_manifest.sh Modified: trunk/MANIFEST.in Log: updating MANIFEST.in Modified: trunk/MANIFEST.in =================================================================== --- trunk/MANIFEST.in 2009-01-01 00:32:11 UTC (rev 5314) +++ trunk/MANIFEST.in 2009-01-01 01:12:34 UTC (rev 5315) @@ -1,8 +1,20 @@ -# This automatically generated by new_manifest.sh +# Use .add_data_files and .add_data_dir methods in a appropriate +# setup.py files to include non-python files such as documentation, +# data, etc files to distribution. Avoid using MANIFEST.in for that. # -# Note: for files required to build extensions, you probably want to -# place them in the Extension depend list, rather than in this file. -# +include MANIFEST.in +include *.txt +include setupscons.py +include setupegg.py include setup.py -include *.txt include scipy/*.py +## Adding scons build relateed files not found by distutils +#recursive-include numpy/core/code_generators *.py +#include numpy/core/include/numpy/numpyconfig.h.in +#recursive-include numpy SConstruct +# Add documentation: we don't use add_data_dir since we do not want to include +# this at installation, only for sdist-generated tarballs +include doc/Makefile doc/postprocess.py +recursive-include doc/release * +recursive-include doc/source * +recursive-include doc/sphinxext * Deleted: trunk/new_manifest.sh =================================================================== --- trunk/new_manifest.sh 2009-01-01 00:32:11 UTC (rev 5314) +++ trunk/new_manifest.sh 2009-01-01 01:12:34 UTC (rev 5315) @@ -1,19 +0,0 @@ -#!/bin/sh - -# This little script re-generates MANIFEST.in to include files that -# wouldn't otherwise get picked up by distutils. This is relevant when -# building source distributions using "python setup.py sdist", which -# would otherwise leave these files out. - -MANIFEST_IN=MANIFEST.in - -cat < $MANIFEST_IN -# This automatically generated by new_manifest.sh -# -# Note: for files required to build extensions, you probably want to -# place them in the Extension depend list, rather than in this file. -# -include setup.py -include *.txt -include scipy/*.py -EOF