def sym_tri_eigen(diags, select_indices=None): """ Compute eigenvalues of a symmetric tridiagonal matrix using `scipy.linalg.eigvals_banded()`. """ if select_indices is not None: n = diags.shape[1] select_indices = nm.minimum(select_indices, n) eigs = eigvals_banded(diags, lower=True, select='i', select_range=select_indices) else: eigs = eigvals_banded(diags, lower=True, select='a') return eigs
def problem1(l): ''' print the answer to problem 1 in the Beam buckling lab. Inputs: l -- length of the beam in feet ''' # initialize constants, do unit conversion r = 1.0 E = 4.35*r*12**2*10**6 L = l I = np.pi*r**4/4 n = 1000 h = L/n # build the tri-diagonal matrix diag = -2*np.ones(n)*E*I/h**2 odiag = np.ones(n-1)*E*I/h**2 band = np.zeros((2,n)) band[0,1:] = -odiag band[1,:] = -diag # calculate and print smallest eigenvalue evals = la.eigvals_banded(band) print evals[0] # print the analytically calculated answer print np.pi**2*E*I/L**2
def log_likelihood(self, p): """Returns the log-likelihood of the data under the model, but efficiently. """ p = self.to_params(p) try: alpha = self._alpha_matrix(p) beta = self._beta_matrix(p, alpha=alpha) except np.linalg.LinAlgError: warnings.warn('exception in alpha/beta computation, probably too-small timescales', BadParameterWarning) return np.NINF xs = np.zeros(self.n) al.log_likelihood_xs_loop(self.n, self.p, alpha, self.ys - p['mu'], xs) try: evals = sl.eigvals_banded(beta, lower=False) if np.any(evals <= 0): warnings.warn('found non-positive-definite transformed covariance', BadParameterWarning) return np.NINF log_evals = np.log(evals) return -0.5*self.n*np.log(2.0*np.pi) - 0.5*np.sum(log_evals) - 0.5*np.dot(xs, sl.solveh_banded(beta, xs, lower=False)) except sl.LinAlgError: warnings.warn('exception in log-likelihood computation, probably singular cov', BadParameterWarning) return np.NINF
def problem1(l): ''' print the answer to problem 1 in the Beam buckling lab. Inputs: l -- length of the beam in feet ''' # initialize constants, do unit conversion r = 1.0 E = 4.35 * r * 12**2 * 10**6 L = l I = np.pi * r**4 / 4 n = 1000 h = L / n # build the tri-diagonal matrix diag = -2 * np.ones(n) * E * I / h**2 odiag = np.ones(n - 1) * E * I / h**2 band = np.zeros((2, n)) band[0, 1:] = -odiag band[1, :] = -diag # calculate and print smallest eigenvalue evals = la.eigvals_banded(band) print evals[0] # print the analytically calculated answer print np.pi**2 * E * I / L**2
def _dpss(N, half_nbw, Kmax): """Compute DPSS windows.""" # here we want to set up an optimization problem to find a sequence # whose energy is maximally concentrated within band [-W,W]. # Thus, the measure lambda(T,W) is the ratio between the energy within # that band, and the total energy. This leads to the eigen-system # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest # eigenvalue is the sequence with maximally concentrated energy. The # collection of eigenvectors of this system are called Slepian # sequences, or discrete prolate spheroidal sequences (DPSS). Only the # first K, K = 2NW/dt orders of DPSS will exhibit good spectral # concentration # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem] # Here I set up an alternative symmetric tri-diagonal eigenvalue # problem such that # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1) # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1] # and the first off-diagonal = t(N-t)/2, t=[1,2,...,N-1] # [see Percival and Walden, 1993] nidx = np.arange(N, dtype='d') W = float(half_nbw) / N diagonal = ((N - 1 - 2 * nidx) / 2.)**2 * np.cos(2 * np.pi * W) off_diag = np.zeros_like(nidx) off_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2. # put the diagonals in LAPACK "packed" storage ab = np.zeros((2, N), 'd') ab[1] = diagonal ab[0, 1:] = off_diag[:-1] # only calculate the highest Kmax eigenvalues w = linalg.eigvals_banded(ab, select='i', select_range=(N - Kmax, N - 1)) w = w[::-1] # find the corresponding eigenvectors via inverse iteration t = np.linspace(0, np.pi, N) dpss = np.zeros((Kmax, N), 'd') for k in range(Kmax): dpss[k] = tridi_inverse_iteration(diagonal, off_diag, w[k], x0=np.sin((k + 1) * t)) # By convention (Percival and Walden, 1993 pg 379) # * symmetric tapers (k=0,2,4,...) should have a positive average. # * antisymmetric tapers should begin with a positive lobe fix_symmetric = (dpss[0::2].sum(axis=1) < 0) for i, f in enumerate(fix_symmetric): if f: dpss[2 * i] *= -1 # rather than test the sign of one point, test the sign of the # linear slope up to the first (largest) peak pk = np.argmax(np.abs(dpss[1::2, :N // 2]), axis=1) for i, p in enumerate(pk): if np.sum(dpss[2 * i + 1, :p]) < 0: dpss[2 * i + 1] *= -1 return dpss
def grid_guess(self): J = self.op['J'] if self.symmetric: J_banded = sparse_symm_to_banded(J) self.grid = np.sort(linear.eigvals_banded(J_banded).real) else: J_dense = J.todense() self.grid = np.sort(linear.eigvals(J_dense).real) self.ngrid = len(self.grid)
def _dpss(N, half_nbw, Kmax): """Compute DPSS windows.""" # here we want to set up an optimization problem to find a sequence # whose energy is maximally concentrated within band [-W,W]. # Thus, the measure lambda(T,W) is the ratio between the energy within # that band, and the total energy. This leads to the eigen-system # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest # eigenvalue is the sequence with maximally concentrated energy. The # collection of eigenvectors of this system are called Slepian # sequences, or discrete prolate spheroidal sequences (DPSS). Only the # first K, K = 2NW/dt orders of DPSS will exhibit good spectral # concentration # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem] # Here I set up an alternative symmetric tri-diagonal eigenvalue # problem such that # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1) # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1] # and the first off-diagonal = t(N-t)/2, t=[1,2,...,N-1] # [see Percival and Walden, 1993] nidx = np.arange(N, dtype='d') W = float(half_nbw) / N diagonal = ((N - 1 - 2 * nidx) / 2.) ** 2 * np.cos(2 * np.pi * W) off_diag = np.zeros_like(nidx) off_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2. # put the diagonals in LAPACK "packed" storage ab = np.zeros((2, N), 'd') ab[1] = diagonal ab[0, 1:] = off_diag[:-1] # only calculate the highest Kmax eigenvalues w = linalg.eigvals_banded(ab, select='i', select_range=(N - Kmax, N - 1)) w = w[::-1] # find the corresponding eigenvectors via inverse iteration t = np.linspace(0, np.pi, N) dpss = np.zeros((Kmax, N), 'd') for k in range(Kmax): dpss[k] = tridi_inverse_iteration(diagonal, off_diag, w[k], x0=np.sin((k + 1) * t)) # By convention (Percival and Walden, 1993 pg 379) # * symmetric tapers (k=0,2,4,...) should have a positive average. # * antisymmetric tapers should begin with a positive lobe fix_symmetric = (dpss[0::2].sum(axis=1) < 0) for i, f in enumerate(fix_symmetric): if f: dpss[2 * i] *= -1 # rather than test the sign of one point, test the sign of the # linear slope up to the first (largest) peak pk = np.argmax(np.abs(dpss[1::2, :N // 2]), axis=1) for i, p in enumerate(pk): if np.sum(dpss[2 * i + 1, :p]) < 0: dpss[2 * i + 1] *= -1 return dpss
def ritz_values(Amul, b, nits): """ Return all computed ritz values as a list of arrays, where the i-th array contains the ritz values at the i-th step """ alpha, beta = lanczos(Amul, b, nits) rvals = [] #This puts the diagonals into the appropriate form for eigvals_banded M = np.zeros((2, nits)) M[0, 1:] = beta[:-1] M[1] = alpha for n in xrange(1, nits + 1): rvals.append(eigvals_banded(M[:, :n])) return rvals
def _find_tapers_from_optimization(n_time_samples_per_window, time_index, half_bandwidth, n_tapers): '''here we want to set up an optimization problem to find a sequence whose energy is maximally concentrated within band [-half_bandwidth, half_bandwidth]. Thus, the measure lambda(T, half_bandwidth) is the ratio between the energy within that band, and the total energy. This leads to the eigen-system (A - (l1)I)v = 0, where the eigenvector corresponding to the largest eigenvalue is the sequence with maximally concentrated energy. The collection of eigenvectors of this system are called Slepian sequences, or discrete prolate spheroidal sequences (DPSS). Only the first K, K = 2NW/dt orders of DPSS will exhibit good spectral concentration [see http://en.wikipedia.org/wiki/Spectral_concentration_problem] Here I set up an alternative symmetric tri-diagonal eigenvalue problem such that (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1) the main diagonal = ([n_time_samples_per_window-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,n_time_samples_per_window-1] and the first off-diagonal = t(n_time_samples_per_window-t)/2, t=[1,2,..., n_time_samples_per_window-1] [see Percival and Walden, 1993]''' diagonal = ( ((n_time_samples_per_window - 1 - 2 * time_index) / 2.) ** 2 * np.cos(2 * np.pi * half_bandwidth)) off_diag = np.zeros_like(time_index) off_diag[:-1] = ( time_index[1:] * (n_time_samples_per_window - time_index[1:]) / 2.) # put the diagonals in LAPACK 'packed' storage ab = np.zeros((2, n_time_samples_per_window), dtype='d') ab[1] = diagonal ab[0, 1:] = off_diag[:-1] # only calculate the highest n_tapers eigenvalues w = eigvals_banded( ab, select='i', select_range=(n_time_samples_per_window - n_tapers, n_time_samples_per_window - 1)) w = w[::-1] # find the corresponding eigenvectors via inverse iteration t = np.linspace(0, np.pi, n_time_samples_per_window) tapers = np.zeros((n_tapers, n_time_samples_per_window), dtype='d') for taper_ind in range(n_tapers): tapers[taper_ind, :] = tridi_inverse_iteration( diagonal, off_diag, w[taper_ind], x0=np.sin((taper_ind + 1) * t)) return tapers
def grid_guess(Jacobi_matrix, symmetric=True): """Returns reasonable Gauss quadrature grid as the Jacobi matrix eigenvalues. For P(z) = [p_{0}(z),...,p_{N}(z)], J.P(z) = z P(z); or p_{N+1}(z) = 0. Parameters ---------- Jacobi_matrix: square self-adjoint tri-diagonal matrix (arbitrary metric) symmetric: T/F A normalised metric implies a self-adjoint matrix is symmetric. """ if symmetric: J_banded = sparse_symm_to_banded(Jacobi_matrix) return (np.sort(linear.eigvals_banded(J_banded).real)).astype(dtype) else: J_dense = Jacobi_matrix.todense() return (np.sort(linear.eigvals(J_dense).real)).astype(dtype)
def test_tridi_inverse_iteration(): import scipy.linalg as la from scipy.sparse import spdiags # set up a spectral concentration eigenvalue problem for testing N = 2000 NW = 4 K = 8 W = float(NW) / N nidx = np.arange(N, dtype='d') ab = np.zeros((2, N), 'd') # store this separately for tridisolve later sup_diag = np.zeros((N, ), 'd') sup_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2. ab[0, 1:] = sup_diag[:-1] ab[1] = ((N - 1 - 2 * nidx) / 2.)**2 * np.cos(2 * np.pi * W) # only calculate the highest Kmax-1 eigenvalues w = la.eigvals_banded(ab, select='i', select_range=(N - K, N - 1)) w = w[::-1] E = np.zeros((K, N), 'd') t = np.linspace(0, np.pi, N) # make sparse tridiagonal matrix for eigenvector check sp_data = np.zeros((3, N), 'd') sp_data[0, :-1] = sup_diag[:-1] sp_data[1] = ab[1] sp_data[2, 1:] = sup_diag[:-1] A = spdiags(sp_data, [-1, 0, 1], N, N) E = np.zeros((K, N), 'd') for j in xrange(K): e = utils.tridi_inverse_iteration(ab[1], sup_diag, w[j], x0=np.sin((j + 1) * t)) b = A * e nt.assert_true( np.linalg.norm(np.abs(b) - np.abs(w[j]*e)) < 1e-8, 'Inverse iteration eigenvector solution is inconsistent with '\ 'given eigenvalue' ) E[j] = e # also test orthonormality of the eigenvectors ident = np.dot(E, E.T) npt.assert_almost_equal(ident, np.eye(K))
def test_tridi_inverse_iteration(): import scipy.linalg as la from scipy.sparse import spdiags # set up a spectral concentration eigenvalue problem for testing N = 2000 NW = 4 K = 8 W = float(NW) / N nidx = np.arange(N, dtype='d') ab = np.zeros((2, N), 'd') # store this separately for tridisolve later sup_diag = np.zeros((N,), 'd') sup_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2. ab[0, 1:] = sup_diag[:-1] ab[1] = ((N - 1 - 2 * nidx) / 2.) ** 2 * np.cos(2 * np.pi * W) # only calculate the highest Kmax-1 eigenvalues w = la.eigvals_banded(ab, select='i', select_range=(N - K, N - 1)) w = w[::-1] E = np.zeros((K, N), 'd') t = np.linspace(0, np.pi, N) # make sparse tridiagonal matrix for eigenvector check sp_data = np.zeros((3,N), 'd') sp_data[0, :-1] = sup_diag[:-1] sp_data[1] = ab[1] sp_data[2, 1:] = sup_diag[:-1] A = spdiags(sp_data, [-1, 0, 1], N, N) E = np.zeros((K,N), 'd') for j in xrange(K): e = utils.tridi_inverse_iteration( ab[1], sup_diag, w[j], x0=np.sin((j+1)*t) ) b = A*e nt.assert_true( np.linalg.norm(np.abs(b) - np.abs(w[j]*e)) < 1e-8, 'Inverse iteration eigenvector solution is inconsistent with '\ 'given eigenvalue' ) E[j] = e # also test orthonormality of the eigenvectors ident = np.dot(E, E.T) npt.assert_almost_equal(ident, np.eye(K))
def _gen_roots_and_weights(n, mu0, an_func, bn_func, f, df, symmetrize, mu): """[x,w] = gen_roots_and_weights(n,an_func,sqrt_bn_func,mu) Returns the roots (x) of an nth order orthogonal polynomial, and weights (w) to use in appropriate Gaussian quadrature with that orthogonal polynomial. The polynomials have the recurrence relation P_n+1(x) = (x - A_n) P_n(x) - B_n P_n-1(x) an_func(n) should return A_n sqrt_bn_func(n) should return sqrt(B_n) mu ( = h_0 ) is the integral of the weight over the orthogonal interval """ k = np.arange(n, dtype='d') c = np.zeros((2, n)) c[0,1:] = bn_func(k[1:]) c[1,:] = an_func(k) x = linalg.eigvals_banded(c, overwrite_a_band=True) # improve roots by one application of Newton's method y = f(n, x) dy = df(n, x) x -= y/dy fm = f(n-1, x) fm /= np.abs(fm).max() dy /= np.abs(dy).max() w = 1.0 / (fm * dy) if symmetrize: w = (w + w[::-1]) / 2 x = (x - x[::-1]) / 2 w *= mu0 / w.sum() if mu: return x, w, mu0 else: return x, w
def test_eigvals_banded(self): """Compare eigenvalues of eigvals_banded with those of linalg.eig.""" w_sym = eigvals_banded(self.bandmat_sym) w_sym = w_sym.real assert_array_almost_equal(sort(w_sym), self.w_sym_lin) w_herm = eigvals_banded(self.bandmat_herm) w_herm = w_herm.real assert_array_almost_equal(sort(w_herm), self.w_herm_lin) # extracting eigenvalues with respect to an index range ind1 = 2 ind2 = 6 w_sym_ind = eigvals_banded(self.bandmat_sym, select='i', select_range=(ind1, ind2)) assert_array_almost_equal(sort(w_sym_ind), self.w_sym_lin[ind1:ind2 + 1]) w_herm_ind = eigvals_banded(self.bandmat_herm, select='i', select_range=(ind1, ind2)) assert_array_almost_equal(sort(w_herm_ind), self.w_herm_lin[ind1:ind2 + 1]) # extracting eigenvalues with respect to a value range v_lower = self.w_sym_lin[ind1] - 1.0e-5 v_upper = self.w_sym_lin[ind2] + 1.0e-5 w_sym_val = eigvals_banded(self.bandmat_sym, select='v', select_range=(v_lower, v_upper)) assert_array_almost_equal(sort(w_sym_val), self.w_sym_lin[ind1:ind2 + 1]) v_lower = self.w_herm_lin[ind1] - 1.0e-5 v_upper = self.w_herm_lin[ind2] + 1.0e-5 w_herm_val = eigvals_banded(self.bandmat_herm, select='v', select_range=(v_lower, v_upper)) assert_array_almost_equal(sort(w_herm_val), self.w_herm_lin[ind1:ind2 + 1])
def test_eigvals_banded(self): """Compare eigenvalues of eigvals_banded with those of linalg.eig.""" w_sym = eigvals_banded(self.bandmat_sym) w_sym = w_sym.real assert_array_almost_equal(sort(w_sym), self.w_sym_lin) w_herm = eigvals_banded(self.bandmat_herm) w_herm = w_herm.real assert_array_almost_equal(sort(w_herm), self.w_herm_lin) # extracting eigenvalues with respect to an index range ind1 = 2 ind2 = 6 w_sym_ind = eigvals_banded(self.bandmat_sym, select='i', select_range=(ind1, ind2) ) assert_array_almost_equal(sort(w_sym_ind), self.w_sym_lin[ind1:ind2+1]) w_herm_ind = eigvals_banded(self.bandmat_herm, select='i', select_range=(ind1, ind2) ) assert_array_almost_equal(sort(w_herm_ind), self.w_herm_lin[ind1:ind2+1]) # extracting eigenvalues with respect to a value range v_lower = self.w_sym_lin[ind1] - 1.0e-5 v_upper = self.w_sym_lin[ind2] + 1.0e-5 w_sym_val = eigvals_banded(self.bandmat_sym, select='v', select_range=(v_lower, v_upper) ) assert_array_almost_equal(sort(w_sym_val), self.w_sym_lin[ind1:ind2+1]) v_lower = self.w_herm_lin[ind1] - 1.0e-5 v_upper = self.w_herm_lin[ind2] + 1.0e-5 w_herm_val = eigvals_banded(self.bandmat_herm, select='v', select_range=(v_lower, v_upper) ) assert_array_almost_equal(sort(w_herm_val), self.w_herm_lin[ind1:ind2+1])
def dpss_windows(N, half_nbw, Kmax, low_bias=True, interp_from=None, interp_kind='linear'): """ Returns the Discrete Prolate Spheroidal Sequences of orders [0,Kmax-1] for a given frequency-spacing multiple NW and sequence length N. Note: Copied from NiTime Parameters ---------- N : int Sequence length half_nbw : float, unitless Standardized half bandwidth corresponding to 2 * half_bw = BW*f0 = BW*N/dt but with dt taken as 1 Kmax : int Number of DPSS windows to return is Kmax (orders 0 through Kmax-1) low_bias : Bool Keep only tapers with eigenvalues > 0.9 interp_from : int (optional) The dpss can be calculated using interpolation from a set of dpss with the same NW and Kmax, but shorter N. This is the length of this shorter set of dpss windows. interp_kind : str (optional) This input variable is passed to scipy.interpolate.interp1d and specifies the kind of interpolation as a string ('linear', 'nearest', 'zero', 'slinear', 'quadratic, 'cubic') or as an integer specifying the order of the spline interpolator to use. Returns ------- v, e : tuple, v is an array of DPSS windows shaped (Kmax, N) e are the eigenvalues Notes ----- Tridiagonal form of DPSS calculation from: Slepian, D. Prolate spheroidal wave functions, Fourier analysis, and uncertainty V: The discrete case. Bell System Technical Journal, Volume 57 (1978), 1371430 """ from scipy import interpolate Kmax = int(Kmax) W = float(half_nbw) / N nidx = np.arange(N, dtype='d') # In this case, we create the dpss windows of the smaller size # (interp_from) and then interpolate to the larger size (N) if interp_from is not None: if interp_from > N: e_s = 'In dpss_windows, interp_from is: %s ' % interp_from e_s += 'and N is: %s. ' % N e_s += 'Please enter interp_from smaller than N.' raise ValueError(e_s) dpss = [] d, e = dpss_windows(interp_from, half_nbw, Kmax, low_bias=False) for this_d in d: x = np.arange(this_d.shape[-1]) I = interpolate.interp1d(x, this_d, kind=interp_kind) d_temp = I(np.linspace(0, this_d.shape[-1] - 1, N, endpoint=False)) # Rescale: d_temp = d_temp / np.sqrt(sum_squared(d_temp)) dpss.append(d_temp) dpss = np.array(dpss) else: # here we want to set up an optimization problem to find a sequence # whose energy is maximally concentrated within band [-W,W]. # Thus, the measure lambda(T,W) is the ratio between the energy within # that band, and the total energy. This leads to the eigen-system # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest # eigenvalue is the sequence with maximally concentrated energy. The # collection of eigenvectors of this system are called Slepian # sequences, or discrete prolate spheroidal sequences (DPSS). Only the # first K, K = 2NW/dt orders of DPSS will exhibit good spectral # concentration # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem] # Here I set up an alternative symmetric tri-diagonal eigenvalue # problem such that # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1) # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1] # and the first off-diagonal = t(N-t)/2, t=[1,2,...,N-1] # [see Percival and Walden, 1993] diagonal = ((N - 1 - 2 * nidx) / 2.) ** 2 * np.cos(2 * np.pi * W) off_diag = np.zeros_like(nidx) off_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2. # put the diagonals in LAPACK "packed" storage ab = np.zeros((2, N), 'd') ab[1] = diagonal ab[0, 1:] = off_diag[:-1] # only calculate the highest Kmax eigenvalues w = linalg.eigvals_banded(ab, select='i', select_range=(N - Kmax, N - 1)) w = w[::-1] # find the corresponding eigenvectors via inverse iteration t = np.linspace(0, np.pi, N) dpss = np.zeros((Kmax, N), 'd') for k in range(Kmax): dpss[k] = tridi_inverse_iteration(diagonal, off_diag, w[k], x0=np.sin((k + 1) * t)) # By convention (Percival and Walden, 1993 pg 379) # * symmetric tapers (k=0,2,4,...) should have a positive average. # * antisymmetric tapers should begin with a positive lobe fix_symmetric = (dpss[0::2].sum(axis=1) < 0) for i, f in enumerate(fix_symmetric): if f: dpss[2 * i] *= -1 # rather than test the sign of one point, test the sign of the # linear slope up to the first (largest) peak pk = np.argmax(np.abs(dpss[1::2, :N // 2]), axis=1) for i, p in enumerate(pk): if np.sum(dpss[2 * i + 1, :p]) < 0: dpss[2 * i + 1] *= -1 # Now find the eigenvalues of the original spectral concentration problem # Use the autocorr sequence technique from Percival and Walden, 1993 pg 390 # compute autocorr using FFT (same as nitime.utils.autocorr(dpss) * N) rxx_size = 2 * N - 1 n_fft = 2 ** int(np.ceil(np.log2(rxx_size))) dpss_fft = fftpack.fft(dpss, n_fft) dpss_rxx = np.real(fftpack.ifft(dpss_fft * dpss_fft.conj())) dpss_rxx = dpss_rxx[:, :N] r = 4 * W * np.sinc(2 * W * nidx) r[0] = 2 * W eigvals = np.dot(dpss_rxx, r) if low_bias: idx = (eigvals > 0.9) if not idx.any(): warn('Could not properly use low_bias, keeping lowest-bias taper') idx = [np.argmax(eigvals)] dpss, eigvals = dpss[idx], eigvals[idx] assert len(dpss) > 0 # should never happen assert dpss.shape[1] == N # old nitime bug return dpss, eigvals
def dpss_windows(N, NW, Kmax, interp_from=None, interp_kind='linear'): """ Returns the Discrete Prolate Spheroidal Sequences of orders [0,Kmax-1] for a given frequency-spacing multiple NW and sequence length N. Paramters --------- N : int sequence length NW : float, unitless standardized half bandwidth corresponding to 2NW = BW*f0 = BW*N/dt but with dt taken as 1 Kmax : int number of DPSS windows to return is Kmax (orders 0 through Kmax-1) interp_from: int (optional) The dpss will can calculated using interpolation from a set of dpss with the same NW and Kmax, but shorter N. This is the length of this shorter set of dpss windows. interp_kind: str (optional) This input variable is passed to scipy.interpolate.interp1d and specifies the kind of interpolation as a string ('linear', 'nearest', 'zero', 'slinear', 'quadratic, 'cubic') or as an integer specifying the order of the spline interpolator to use. Returns ------- v, e : tuple, v is an array of DPSS windows shaped (Kmax, N) e are the eigenvalues Notes ----- Tridiagonal form of DPSS calculation from: Slepian, D. Prolate spheroidal wave functions, Fourier analysis, and uncertainty V: The discrete case. Bell System Technical Journal, Volume 57 (1978), 1371430 """ Kmax = int(Kmax) W = float(NW) / N nidx = np.arange(N, dtype='d') # In this case, we create the dpss windows of the smaller size # (interp_from) and then interpolate to the larger size (N) if interp_from is not None: if interp_from > N: e_s = 'In dpss_windows, interp_from is: %s ' % interp_from e_s += 'and N is: %s. ' % N e_s += 'Please enter interp_from smaller than N.' raise ValueError(e_s) dpss = [] d, e = dpss_windows(interp_from, NW, Kmax) for this_d in d: x = np.arange(this_d.shape[-1]) I = interpolate.interp1d(x, this_d, kind=interp_kind) d_temp = I( np.arange(0, this_d.shape[-1] - 1, float(this_d.shape[-1] - 1) / N)) # Rescale: d_temp = d_temp / np.sqrt(np.sum(d_temp**2)) dpss.append(d_temp) dpss = np.array(dpss) else: # here we want to set up an optimization problem to find a sequence # whose energy is maximally concentrated within band [-W,W]. # Thus, the measure lambda(T,W) is the ratio between the energy within # that band, and the total energy. This leads to the eigen-system # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest # eigenvalue is the sequence with maximally concentrated energy. The # collection of eigenvectors of this system are called Slepian # sequences, or discrete prolate spheroidal sequences (DPSS). Only the # first K, K = 2NW/dt orders of DPSS will exhibit good spectral # concentration # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem] # Here I set up an alternative symmetric tri-diagonal eigenvalue # problem such that # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1) # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1] # and the first off-diagonal = t(N-t)/2, t=[1,2,...,N-1] # [see Percival and Walden, 1993] diagonal = ((N - 1 - 2 * nidx) / 2.)**2 * np.cos(2 * np.pi * W) off_diag = np.zeros_like(nidx) off_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2. # put the diagonals in LAPACK "packed" storage ab = np.zeros((2, N), 'd') ab[1] = diagonal ab[0, 1:] = off_diag[:-1] # only calculate the highest Kmax eigenvalues w = linalg.eigvals_banded(ab, select='i', select_range=(N - Kmax, N - 1)) w = w[::-1] # find the corresponding eigenvectors via inverse iteration t = np.linspace(0, np.pi, N) dpss = np.zeros((Kmax, N), 'd') for k in xrange(Kmax): dpss[k] = utils.tridi_inverse_iteration(diagonal, off_diag, w[k], x0=np.sin((k + 1) * t)) # By convention (Percival and Walden, 1993 pg 379) # * symmetric tapers (k=0,2,4,...) should have a positive average. # * antisymmetric tapers should begin with a positive lobe fix_symmetric = (dpss[0::2].sum(axis=1) < 0) for i, f in enumerate(fix_symmetric): if f: dpss[2 * i] *= -1 fix_skew = (dpss[1::2, 1] < 0) for i, f in enumerate(fix_skew): if f: dpss[2 * i + 1] *= -1 # Now find the eigenvalues of the original spectral concentration problem # Use the autocorr sequence technique from Percival and Walden, 1993 pg 390 dpss_rxx = utils.autocorr(dpss) * N r = 4 * W * np.sinc(2 * W * nidx) r[0] = 2 * W eigvals = np.dot(dpss_rxx, r) return dpss, eigvals
def dpss_windows(N, half_nbw, Kmax, low_bias=True, interp_from=None, interp_kind='linear'): """Compute Discrete Prolate Spheroidal Sequences. Will give of orders [0,Kmax-1] for a given frequency-spacing multiple NW and sequence length N. Note: Copied from NiTime Parameters ---------- N : int Sequence length half_nbw : float, unitless Standardized half bandwidth corresponding to 2 * half_bw = BW*f0 = BW*N/dt but with dt taken as 1 Kmax : int Number of DPSS windows to return is Kmax (orders 0 through Kmax-1) low_bias : Bool Keep only tapers with eigenvalues > 0.9 interp_from : int (optional) The dpss can be calculated using interpolation from a set of dpss with the same NW and Kmax, but shorter N. This is the length of this shorter set of dpss windows. interp_kind : str (optional) This input variable is passed to scipy.interpolate.interp1d and specifies the kind of interpolation as a string ('linear', 'nearest', 'zero', 'slinear', 'quadratic, 'cubic') or as an integer specifying the order of the spline interpolator to use. Returns ------- v, e : tuple, v is an array of DPSS windows shaped (Kmax, N) e are the eigenvalues Notes ----- Tridiagonal form of DPSS calculation from: Slepian, D. Prolate spheroidal wave functions, Fourier analysis, and uncertainty V: The discrete case. Bell System Technical Journal, Volume 57 (1978), 1371430 """ from scipy import interpolate Kmax = int(Kmax) W = float(half_nbw) / N nidx = np.arange(N, dtype='d') # In this case, we create the dpss windows of the smaller size # (interp_from) and then interpolate to the larger size (N) if interp_from is not None: if interp_from > N: e_s = 'In dpss_windows, interp_from is: %s ' % interp_from e_s += 'and N is: %s. ' % N e_s += 'Please enter interp_from smaller than N.' raise ValueError(e_s) dpss = [] d, e = dpss_windows(interp_from, half_nbw, Kmax, low_bias=False) for this_d in d: x = np.arange(this_d.shape[-1]) I = interpolate.interp1d(x, this_d, kind=interp_kind) d_temp = I(np.linspace(0, this_d.shape[-1] - 1, N, endpoint=False)) # Rescale: d_temp = d_temp / np.sqrt(sum_squared(d_temp)) dpss.append(d_temp) dpss = np.array(dpss) else: # here we want to set up an optimization problem to find a sequence # whose energy is maximally concentrated within band [-W,W]. # Thus, the measure lambda(T,W) is the ratio between the energy within # that band, and the total energy. This leads to the eigen-system # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest # eigenvalue is the sequence with maximally concentrated energy. The # collection of eigenvectors of this system are called Slepian # sequences, or discrete prolate spheroidal sequences (DPSS). Only the # first K, K = 2NW/dt orders of DPSS will exhibit good spectral # concentration # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem] # Here I set up an alternative symmetric tri-diagonal eigenvalue # problem such that # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1) # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1] # and the first off-diagonal = t(N-t)/2, t=[1,2,...,N-1] # [see Percival and Walden, 1993] diagonal = ((N - 1 - 2 * nidx) / 2.)**2 * np.cos(2 * np.pi * W) off_diag = np.zeros_like(nidx) off_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2. # put the diagonals in LAPACK "packed" storage ab = np.zeros((2, N), 'd') ab[1] = diagonal ab[0, 1:] = off_diag[:-1] # only calculate the highest Kmax eigenvalues w = linalg.eigvals_banded(ab, select='i', select_range=(N - Kmax, N - 1)) w = w[::-1] # find the corresponding eigenvectors via inverse iteration t = np.linspace(0, np.pi, N) dpss = np.zeros((Kmax, N), 'd') for k in range(Kmax): dpss[k] = tridi_inverse_iteration(diagonal, off_diag, w[k], x0=np.sin((k + 1) * t)) # By convention (Percival and Walden, 1993 pg 379) # * symmetric tapers (k=0,2,4,...) should have a positive average. # * antisymmetric tapers should begin with a positive lobe fix_symmetric = (dpss[0::2].sum(axis=1) < 0) for i, f in enumerate(fix_symmetric): if f: dpss[2 * i] *= -1 # rather than test the sign of one point, test the sign of the # linear slope up to the first (largest) peak pk = np.argmax(np.abs(dpss[1::2, :N // 2]), axis=1) for i, p in enumerate(pk): if np.sum(dpss[2 * i + 1, :p]) < 0: dpss[2 * i + 1] *= -1 # Now find the eigenvalues of the original spectral concentration problem # Use the autocorr sequence technique from Percival and Walden, 1993 pg 390 # compute autocorr using FFT (same as nitime.utils.autocorr(dpss) * N) rxx_size = 2 * N - 1 n_fft = 2**int(np.ceil(np.log2(rxx_size))) dpss_fft = fftpack.fft(dpss, n_fft) dpss_rxx = np.real(fftpack.ifft(dpss_fft * dpss_fft.conj())) dpss_rxx = dpss_rxx[:, :N] r = 4 * W * np.sinc(2 * W * nidx) r[0] = 2 * W eigvals = np.dot(dpss_rxx, r) if low_bias: idx = (eigvals > 0.9) if not idx.any(): warn('Could not properly use low_bias, keeping lowest-bias taper') idx = [np.argmax(eigvals)] dpss, eigvals = dpss[idx], eigvals[idx] assert len(dpss) > 0 # should never happen assert dpss.shape[1] == N # old nitime bug return dpss, eigvals
def dpss_windows(N, NW, Kmax, interp_from=None, interp_kind='linear'): """ Returns the Discrete Prolate Spheroidal Sequences of orders [0,Kmax-1] for a given frequency-spacing multiple NW and sequence length N. Paramters --------- N : int sequence length NW : float, unitless standardized half bandwidth corresponding to 2NW = BW*f0 = BW*N/dt but with dt taken as 1 Kmax : int number of DPSS windows to return is Kmax (orders 0 through Kmax-1) interp_from: int (optional) The dpss will can calculated using interpolation from a set of dpss with the same NW and Kmax, but shorter N. This is the length of this shorter set of dpss windows. interp_kind: str (optional) This input variable is passed to scipy.interpolate.interp1d and specifies the kind of interpolation as a string ('linear', 'nearest', 'zero', 'slinear', 'quadratic, 'cubic') or as an integer specifying the order of the spline interpolator to use. Returns ------- v, e : tuple, v is an array of DPSS windows shaped (Kmax, N) e are the eigenvalues Notes ----- Tridiagonal form of DPSS calculation from: Slepian, D. Prolate spheroidal wave functions, Fourier analysis, and uncertainty V: The discrete case. Bell System Technical Journal, Volume 57 (1978), 1371430 """ Kmax = int(Kmax) W = float(NW) / N nidx = np.arange(N, dtype='d') # In this case, we create the dpss windows of the smaller size # (interp_from) and then interpolate to the larger size (N) if interp_from is not None: if interp_from>N: e_s = 'In dpss_windows, interp_from is: %s ' % interp_from e_s += 'and N is: %s. ' % N e_s += 'Please enter interp_from smaller than N.' raise ValueError(e_s) dpss = [] d, e = dpss_windows(interp_from, NW, Kmax) for this_d in d: x = np.arange(this_d.shape[-1]) I = interpolate.interp1d(x, this_d, kind=interp_kind) d_temp = I(np.arange(0, this_d.shape[-1] - 1, float(this_d.shape[-1] - 1) / N)) # Rescale: d_temp = d_temp / np.sqrt(np.sum(d_temp ** 2)) dpss.append(d_temp) dpss = np.array(dpss) else: # here we want to set up an optimization problem to find a sequence # whose energy is maximally concentrated within band [-W,W]. # Thus, the measure lambda(T,W) is the ratio between the energy within # that band, and the total energy. This leads to the eigen-system # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest # eigenvalue is the sequence with maximally concentrated energy. The # collection of eigenvectors of this system are called Slepian sequences, # or discrete prolate spheroidal sequences (DPSS). Only the first K, # K = 2NW/dt orders of DPSS will exhibit good spectral concentration # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem] # Here I set up an alternative symmetric tri-diagonal eigenvalue problem # such that # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1) # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1] # and the first off-diagonal = t(N-t)/2, t=[1,2,...,N-1] # [see Percival and Walden, 1993] diagonal = ((N - 1 - 2 * nidx) / 2.) ** 2 * np.cos(2 * np.pi * W) off_diag = np.zeros_like(nidx) off_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2. # put the diagonals in LAPACK "packed" storage ab = np.zeros((2, N), 'd') ab[1] = diagonal ab[0, 1:] = off_diag[:-1] # only calculate the highest Kmax eigenvalues w = linalg.eigvals_banded(ab, select='i', select_range=(N - Kmax, N - 1)) w = w[::-1] # find the corresponding eigenvectors via inverse iteration t = np.linspace(0, np.pi, N) dpss = np.zeros((Kmax, N), 'd') for k in xrange(Kmax): dpss[k] = utils.tridi_inverse_iteration( diagonal, off_diag, w[k], x0=np.sin((k + 1) * t) ) # By convention (Percival and Walden, 1993 pg 379) # * symmetric tapers (k=0,2,4,...) should have a positive average. # * antisymmetric tapers should begin with a positive lobe fix_symmetric = (dpss[0::2].sum(axis=1) < 0) for i, f in enumerate(fix_symmetric): if f: dpss[2 * i] *= -1 fix_skew = (dpss[1::2, 1] < 0) for i, f in enumerate(fix_skew): if f: dpss[2 * i + 1] *= -1 # Now find the eigenvalues of the original spectral concentration problem # Use the autocorr sequence technique from Percival and Walden, 1993 pg 390 dpss_rxx = utils.autocorr(dpss) * N r = 4 * W * np.sinc(2 * W * nidx) r[0] = 2 * W eigvals = np.dot(dpss_rxx, r) return dpss, eigvals
alpha_rational = approx2(alpha, maxd) p = np.float(alpha_rational.numerator) q = np.float(alpha_rational.denominator) #print str(alpha) + ', ' + str(p) + '/' + str(q) new_maxd = maxd while p < min_points: p += q * np.ceil((min_points - p) / q) # print str(p/q) + ', ' + str(alpha) + ': ' + str(p) + '/' + str(q) if p > 1: A = np.zeros([2, p], dtype=np.complex128) for n in range(np.int(p)): A[1, n] = 2.0 * V2 * np.cos(q * b * k[1] / p + 2 * np.pi * np.float(n) * q / p) if n < (p - 1): A[0, n + 1] = V1 * np.exp(np.complex(0.0, q * a * k[0] / p)) d = eigvals_banded(A) ds = np.sort(d) ax.plot(alpha * np.ones(p), ds, symbols[kidx], linewidth=0.5, markersize=1.0) plt.xlabel(r'$\alpha$') plt.ylabel(r'$E$') fig.show()
ax = fig.add_subplot(1, 1, 1) symbols = [".b", ".r"] for kidx in range(len(ks)): k = ks[kidx] for alpha in np.arange(1.0 / steps, 1.0, 1.0 / steps): alpha_rational = approx2(alpha, maxd) p = np.float(alpha_rational.numerator) q = np.float(alpha_rational.denominator) # print str(alpha) + ', ' + str(p) + '/' + str(q) new_maxd = maxd while p < min_points: p += q * np.ceil((min_points - p) / q) # print str(p/q) + ', ' + str(alpha) + ': ' + str(p) + '/' + str(q) if p > 1: A = np.zeros([2, p], dtype=np.complex128) for n in range(np.int(p)): A[1, n] = 2.0 * V2 * np.cos(q * b * k[1] / p + 2 * np.pi * np.float(n) * q / p) if n < (p - 1): A[0, n + 1] = V1 * np.exp(np.complex(0.0, q * a * k[0] / p)) d = eigvals_banded(A) ds = np.sort(d) ax.plot(alpha * np.ones(p), ds, symbols[kidx], linewidth=0.5, markersize=1.0) plt.xlabel(r"$\alpha$") plt.ylabel(r"$E$") fig.show()
return rvals if __name__ == "__main__": n = 1000 nits = 40 #A = np.random.random((n,n)) #A = A.dot(A.T) #Construct the matrix ds = [ np.ones(n - 100), np.ones(n - 1), np.sqrt(np.arange(1, n + 1)), np.ones(n - 1), np.ones(n - 100) ] A = diags(ds, offsets=[-100, -1, 0, 1, 100]) b = np.ones(n) Amul = lambda x: A.dot(x) rvals = ritz_values(Amul, b, nits) #Convert the matrix A into the wierd form required by eigvals_banded M = np.zeros((101, n)) M[-1] = ds[2] M[-2, 1:] = ds[1] M[0, 100:] = ds[0] print "Eigenvalue of A from 36.3 obtained after {0} iterations: {1:.7f}".format( nits, rvals[-1][0]) #This call will get only the smallest eigenvalue print "True smallest eigenvalue (according to scipy): {0:.7f}".format( eigvals_banded(M, select='i', select_range=(0, 0))[0])
for n in xrange(1, nits + 1): rvals.append(eigvals_banded(M[:, :n])) return rvals if __name__ == "__main__": n = 1000 nits = 40 #A = np.random.random((n,n)) #A = A.dot(A.T) ds = [ np.ones(n - 100), np.ones(n - 1), np.sqrt(np.arange(1, n + 1)), np.ones(n - 1), np.ones(n - 100) ] A = diags(ds, offsets=[-100, -1, 0, 1, 100]) b = np.random.random(n) Amul = lambda x: A.dot(x) rvals = ritz_values(Amul, b, nits) M = np.zeros((101, n)) M[-1] = ds[2] M[-2, 1:] = ds[1] M[0, 100:] = ds[0] print "Eigenvalue of A from 36.3 obtained after {} iterations: {}".format( nits, rvals[-1][0]) print "True smallest eigenvalue (according to scipy): {}".format( eigvals_banded(M, select='v', select_range=(-1., 1.))[0])
def HH_HO_eigvals(NMax, K, D): from numpy import arange, sqrt, vstack from scipy.linalg import eigvals_banded nmax = (NMax-K) // 2 n = arange(nmax+1) return eigvals_banded(vstack((2 * n + K + D / 2., sqrt((n + 1) * (n + K + D / 2.)))), lower=True)