def qrm3(X, maxiter=15000, debug=False): """ First compute similar matrix in Hessenberg form, then compute the Eigenvalues and Eigenvectors using the QR-Method. Parameters: - X: square numpy ndarray. Returns: - Eigenvalues of A. - Eigenvectors of A. """ n, m = X.shape assert n == m # First stage: transform to upper Hessenberg-matrix. T = lin.hessenberg(X) conv = False k = 0 # Second stage: perform QR-transformations. while (not conv) and (k < maxiter): k += 1 Q, R = helpers.qr_factorize(T - T[n - 1, n - 1] * np.eye(n)) T = R.dot(Q) + T[n - 1, n - 1] * np.eye(n) conv = np.alltrue(np.isclose(np.tril(T, k=-1), np.zeros((n, n)))) if not conv: warnings.warn("Convergence was not reached. Consider raising maxiter.") if debug: return k Evals = T.diagonal() order = np.abs(Evals).argsort()[::-1] return Evals[order], Q[order, :]
def qr_algorithm(A, N=50, tol=1e-12): """Compute the eigenvalues of A via the QR algorithm. Parameters: A ((n,n) ndarray): A square matrix. N (int): The number of iterations to run the QR algorithm. tol (float): The threshold value for determining if a diagonal S_i block is 1x1 or 2x2. Returns: ((n,) ndarray): The eigenvalues of A. """ n=np.shape(A)[0] S=la.hessenberg(A) for k in range(N): Q,R=la.qr(S) S=R@Q eigs=[] i=0 while i<n: if S[i,i] == S[-1,-1] or np.abs(S[i+1,i])<tol: eigs.append(S[i,i]) elif np.shape(S[i]) == (2,2): sqrt=cmath.sqrt((S[i,i][0,0]+S[i,i][1,1])**2-4*(S[i,i][0,0]*S[i,i][1,1]-(S[i,i][1,0]*S[i,i][0,1])))/(2*S[i,i][0,0]) eigs.append((S[i,i][0,0]+S[i,i][1,1])/(2*S[i,i][0,0])+sqrt) eigs.append((S[i,i][0,0]+S[i,i][1,1])/(2*S[i,i][0,0])-sqrt) i=i+1 i=i+1 return eigs
def QR_algorithm(A, niter, tol): """Return the eigenvalues of A using the QR algorithm.""" A = la.hessenberg(A) m, n = A.shape eigen_vals = [] for x in xrange(0, niter): Q, R = la.qr(A) A_new = np.dot(R, Q) A = A_new x = 0 while x < m: if x == m - 1: eigen_vals.append(A[x][x]) break elif abs(A[x + 1][x]) < tol: eigen_vals.append(A[x][x]) else: a = A[x][x] b = A[x][x + 1] c = A[x + 1][x] d = A[x + 1][x + 1] t = a + d d = a * d - b * c eigen_vals.append(t / 2.0 + scimath.sqrt(t**2 / (4 - d))) eigen_vals.append(t / 2.0 - scimath.sqrt(t**2 / (4 - d))) x += 1 x += 1 return eigen_vals
def eig(A, normal = False, iter = 100): '''Finds eigenvalues of an nxn array A. If A is normal, QRalg.eig may also return eigenvectors. Parameters ---------- A : nxn array May be real or complex normal : bool, optional Set to True if A is normal and you want to calculate the eigenvectors. iter : positive integer, optional Returns ------- v : 1xn array of eigenvectors, may be real or complex Q : (only returned if normal = True) nxn array whose columns are eigenvectors, s.t. A*Q = Q*diag(v) real if A is real, complex if A is complex For more on the QR algorithm, see Eigenvalue Solvers lab. ''' def getSchurEig(A): #Find the eigenvalues of a Schur form matrix. These are the #elements on the main diagonal, except where there's a 2x2 #block on the main diagonal. Then we have to find the #eigenvalues of that block. D = sp.diag(A).astype(complex) #Find all the 2x2 blocks: LD = sp.diag(A,-1) index = sp.nonzero(abs(LD)>.01)[0] #is this a good tolerance? #Find the eigenvalues of those blocks: a = 1 b = -D[index]-D[index+1] c = D[index]*D[index+1] - A[index,index+1]*LD[index] discr = sp.sqrt(b**2-4*a*c) #Fill in vector D with those eigenvalues D[index] = (-b + discr)/(2*a) D[index+1] = (-b - discr)/(2*a) return D n,n = A.shape I = sp.eye(n) A,Q = hessenberg(A,True) if normal == False: for i in sp.arange(iter): s = A[n-1,n-1].copy() Qi,R = la.qr(A-s*I) A = sp.dot(R,Qi) + s*I v = getSchurEig(A) return v elif normal == True: for i in sp.arange(iter): s = A[n-1,n-1].copy() Qi,R = la.qr(A-s*I) A = sp.dot(R,Qi) + s*I Q = sp.dot(Q,Qi) v = sp.diag(A) return v,Q
def test_simple_complex(self): a = [[-149, -50,-154], [ 537, 180j, 546], [ -27j, -9, -25]] h,q = hessenberg(a,calc_q=1) h1 = dot(transp(conj(q)),dot(a,q)) assert_array_almost_equal(h1,h)
def QR_algorithm(A,niter,tol): """Return the eigenvalues of A using the QR algorithm.""" H = la.hessenberg(A) for i in xrange(niter): Q,R = la.qr(H) H = np.dot(R,Q) S = H print S eigenvalues = [] i = 0 while i < S.shape[0]: if i == S.shape[0]-1: eigenvalues.append(S[i,i]) elif abs(S[i+1,i]) < tol: eigenvalues.append(S[i,i]) else: a = S[i,i] b = S[i,i+1] c = S[i+1,i] d = S[i+1,i+1] B = -1*(a+d) C = a*d-b*c eigen_plus = (-B + sm.sqrt(B**2 - 4*C))/2. eigen_minus = (-B - sm.sqrt(B**2 - 4*C))/2. eigenvalues.append(eigen_plus) eigenvalues.append(eigen_minus) i+=1 i+=1 return eigenvalues
def qr_algorithm(A, N=50, tol=1e-12): """Compute the eigenvalues of A via the QR algorithm. Parameters: A ((n,n) ndarray): A square matrix. N (int): The number of iterations to run the QR algorithm. tol (float): The threshold value for determining if a diagonal S_i block is 1x1 or 2x2. Returns: ((n,) ndarray): The eigenvalues of A. """ m, n = A.shape #initialize m,n S = la.hessenberg(A) #Put A in upper Hessenberg form for k in range(N): Q, R = la.qr(S) #Get QR decomposition of A S = R.dot(Q) #Recombine R[k] and Q[k] into A[k+1] eigenvalues = [] #initialize empty list of eigenvalues i = 0 while i < n: if i == n - 1 or abs(S[i + 1][i] < tol): eigenvalues.append(S[i][i]) else: #use quadratic formula to get two eigenvalues b = -1 * (S[i, i] + S[i + 1, i + 1]) c = (S[i, i] * S[i + 1, i + 1] - S[i, i + 1] * S[i + 1, i]) eigenvalues.append((-1 * b + cmath.sqrt(b**2 - 4 * c)) / 2) eigenvalues.append((-1 * b - cmath.sqrt(b**2 - 4 * c)) / 2) i += 1 i += 1 #move to the next S[i] return np.array(eigenvalues) #return array of eigenvalues
def QR_Wilkinson(A): eig = [] A = linalg.hessenberg(A) QR_steps = 0 for i in range(A.shape[0], 0, -1): k = 0 while ((abs(A[i - 2, i - 1]) > epsilon * (abs(A[i - 2, i - 1] + A[i - 1, i - 1])))): k = k + 1 if k > 1000: print("Endless") break A_u = A[i - 2:i, i - 2:i] ew, ev = np.linalg.eig(A_u) if (abs(ew[0] - A_u[1, 1]) > abs(ew[1] - A_u[1, 1])): k = ew[1] else: k = ew[0] A = A - np.identity(A.shape[0]) * k Q, R = np.linalg.qr(A) QR_steps = QR_steps + 1 A = R @ Q + np.identity(A.shape[0]) * k eig.append(A[i - 1, i - 1]) return eig, QR_steps
def qr_algorithm(A, N=50, tol=1e-12): """Compute the eigenvalues of A via the QR algorithm. Parameters: A ((n,n) ndarray): A square matrix. N (int): The number of iterations to run the QR algorithm. tol (float): The threshold value for determining if a diagonal S_i block is 1x1 or 2x2. Returns: ((n,) ndarray): The eigenvalues of A. """ m, n = A.shape S = la.hessenberg(A) for k in range(N): Q, R = la.qr(S) S = R @ Q eigs = [] i = 0 while i < n: if i == n - 1 or abs(S[i + 1][i]) < tol: eigs.append(S[i][i]) else: a = S[i][i] b = S[i][i + 1] c = S[i + 1][i] d = S[i + 1][i + 1] e1 = ((a + d) + cmath.sqrt((a + d)**2 - 4 * (a * d - b * c))) / 2 e2 = ((a + d) - cmath.sqrt((a + d)**2 - 4 * (a * d - b * c))) / 2 eigs.append(e1) eigs.append(e2) i += 1 i += 1 return eigs
def test_simple(self): a = [[-149, -50, -154], [537, 180, 546], [-27, -9, -25]] h1 = [[-149.0000, 42.2037, -156.3165], [-537.6783, 152.5511, -554.9272], [0, 0.0728, 2.4489]] h, q = hessenberg(a, calc_q=1) assert_array_almost_equal(dot(transp(q), dot(a, q)), h) assert_array_almost_equal(h, h1, decimal=4)
def test_random_complex(self): n = 20 for k in range(2): a = random([n,n])+1j*random([n,n]) h,q = hessenberg(a,calc_q=1) h1 = dot(transp(conj(q)),dot(a,q)) assert_array_almost_equal(h1,h)
def qr_algorithm(A, N=50, tol=1e-12): """Compute the eigenvalues of A via the QR algorithm. Parameters: A ((n,n) ndarray): A square matrix. N (int): The number of iterations to run the QR algorithm. tol (float): The threshold value for determining if a diagonal S_i block is 1x1 or 2x2. Returns: ((n,) ndarray): The eigenvalues of A. """ m, n = A.shape S = la.hessenberg(A) for k in range(N): Q, R = la.qr(S) S = R @ Q eigs = [] i = 0 while i < n: if i == len(S) - 1 or S[i + 1][i] < tol: eigs.append(S[i][i]) else: b = -(S[i][i] + S[i + 1][i + 1]) c = la.det(S[i:i + 2, i:i + 2]) eigs.append((-b + cmath.sqrt(b**2 - 4 * c)) / 2) eigs.append((-b - cmath.sqrt(b**2 - 4 * c)) / 2) i = i + 1 i = i + 1 return eigs
def importModel(self): """ Import open-loop SISO model (.jac file) include simplified ameloadj code that doesn't look into other auxiliary files (e.g. .la) """ # turn off inputs self.inputList.clear() self.outputList.clear() self.resList.clear() self.tLinList.clear() self.inputList.setEnabled(False) self.outputList.setEnabled(False) self.resList.setEnabled(False) self.tLinList.setEnabled(False) # file selection widget cwd = os.path.dirname(self.filename) dlg = QtWidgets.QFileDialog(self, 'Select .jac file of open-loop, SISO model', cwd, '*.jac*') dlg.exec_() file = dlg.selectedFiles() if len(file) == 0: # loading canceled, back to start self.initUI() return else: # load file (using simplified version of ameloadj to restrict parsing to .jac file only) try: A, B, C, D = ameloadjlight(file[0]) B = B[0] D = D[0] A = np.matrix(A) B = np.matrix(B) C = np.matrix(C) D = np.matrix(D) # Use Hessenberg decomposition to improve computation robustness for large systems H, Q = hessenberg(A, calc_q=True) H = np.matrix(H) Q = np.matrix(Q) ol = signal.lti(H, Q.H * B, C * Q, D) # ol = signal.lti(A, B, C, D) # save and plot self.OL = ol self.matchIO = 1 self.light.setLight(2) self.resList.addItem(os.path.basename(file[0])) self.message.setText("File imported successfully") # move to next step with checkPlant self.checkPlant() except: # show error message and return errorDlg = ErrorDlg(4, os.path.basename(file[0])) errorDlg.exec_() self.initUI() return
def test_simple2(self): a = [[1, 2, 3, 4, 5, 6, 7], [0, 2, 3, 4, 6, 7, 2], [0, 2, 2, 3, 0, 3, 2], [0, 0, 2, 8, 0, 0, 2], [0, 3, 1, 2, 0, 1, 2], [0, 1, 2, 3, 0, 1, 0], [0, 0, 0, 0, 0, 1, 2]] h, q = hessenberg(a, calc_q=1) assert_array_almost_equal(dot(transp(q), dot(a, q)), h)
def test_random_complex(self): n = 20 for k in range(2): a = random([n, n]) + 1j * random([n, n]) h, q = hessenberg(a, calc_q=1) h1 = dot(transp(conj(q)), dot(a, q)) assert_array_almost_equal(h1, h)
def QR_algorithm(A, niter, tol): """Return the eigenvalues of A using the QR algorithm.""" A = la.hessenberg(A).astype(float) eigenvalues = [] n = 0 for i in xrange(1, niter): Q, R = la.qr(A) A = np.dot(np.dot(la.inv(Q), A), Q) while n < np.shape(A)[1]: if n == np.shape(A)[1] - 1: eigenvalues.append(A[n][n]) elif abs(A[n + 1][n]) < tol: eigenvalues.append(A[n][n]) else: two_two = A[n:n + 2, n:n + 2] a = 1 b = -1 * (two_two[0][0] + two_two[1][1]) c = la.det(two_two) x = (-b + (scimath.sqrt(b**2 - 4 * a * c))) / 2 x2 = (-b - (scimath.sqrt(b**2 - 4 * a * c))) / 2 eigenvalues.append(x) eigenvalues.append(x2) n += 1 n += 1 return eigenvalues
def calcOpenLoop(self): """ compute open-loop response from closed-loop in state-space format :return: """ # compute open-loop response cl = self.CL (a, b, c, d) = (cl.A, cl.B, cl.C, cl.D) a = np.matrix(a) b = np.matrix(b) c = np.matrix(c) d = np.matrix(d) tmp = float(inv(1 - d)) A = a + b * c * tmp B = b + b * d * tmp C = c * tmp D = d * tmp # Use Hessenberg decomposition to improve computation robustness for large systems H, Q = hessenberg(A, calc_q=True) H = np.matrix(H) Q = np.matrix(Q) ol = signal.lti(H, Q.H * B, C * Q, D) # ol = signal.lti(A, B, C, D) # save self.OL = ol # move to next step with checkPlant self.checkPlant()
def qr_algorithm(A, N=50, tol=1e-12): """Compute the eigenvalues of A via the QR algorithm. Inputs: A ((n,n) ndarray): A square matrix. N (int): The number of iterations to run the QR algorithm. tol (float): The threshold value for determining if a diagonal block is 1x1 or 2x2. Returns: ((n, ) ndarray): The eigenvalues of A. """ """EQUATION 8.7 should have (a+d) instead of ad""" m, n = A.shape S = la.hessenberg(A) for k in xrange(N): Q, R = la.qr(S, mode="economic") S = R.dot(Q) eigs = [] i = 0 while i < n: if i == n - 1 or np.abs(S[i + 1, i]) < tol: eigs.append(S[i, i]) else: a = S[i, i] b = S[i, i + 1] c = S[i + 1, i] d = S[i + 1, i + 1] evalue1 = (a + d + sqrt((a + d)**2 - 4 * (a * d - b * c))) / 2 evalue2 = (a + d - sqrt((a + d)**2 - 4 * (a * d - b * c))) / 2 eigs.append(evalue1) eigs.append(evalue2) i += 1 #If s is 2x2 want to skip entire thing i += 1 return eigs
def _construct_hessenberg(self, cutoff): """ Performs the tridiagonalization up to 'cutoff' diagonal elements without computing the transformation matrix """ T = hessenberg(self.A) diag = np.diag(T)[:cutoff] offdiag = np.diag(T, k=-1)[:cutoff - 1] return diag, offdiag
def test(self): matrix = mnaMat("2. 0 2 3; 1 4 2 3; 2 5 6 3; 4 5 4 8") oH = sc.hessenberg(matrix) H = QRAlgorithm.HessenbergReduction(matrix) oVa, _ = np.linalg.eig(matrix) Va, _ = np.linalg.eig(H) assertAbsEqualMatrix(np.sort(oVa), np.sort(Va)) assertEqualMatrix(H, oH)
def test(self): matrix = mnaMat("2. 0 2 3; 1 4 2 3; 2 5 6 3; 4 5 4 8") oH = sc.hessenberg(matrix) H, U = QRAlgorithm.HessenbergReductionWithReflector(matrix) oVa, oVe = np.linalg.eig(matrix) Va, Ve = np.linalg.eig(H) assertAbsEqualMatrix(H, oH) assertAbsEqualMatrix(np.sort(oVa), np.sort(Va)) assertAbsEqualMatrix(oVe, U.dot(Ve))
def main(): a = np.asmatrix(la.hilbert(4)) h = tridiag(a) h_std = la.hessenberg(a) print("Solution:") print(h) print('\n') print("Standard Solution:") print(h_std)
def _construct_hessenberg_with_trafo(self, cutoff): """ Performs the tridiagonalization up to 'cutoff' diagonal elements, while also computing the transformation matrix """ T, Q = hessenberg(self.A, calc_q=True) diag = np.diag(T)[:cutoff] offdiag = np.diag(T, k=-1)[:cutoff - 1] return diag, offdiag, Q[:, :cutoff]
def test_simple2(self): a = [[1,2,3,4,5,6,7], [0,2,3,4,6,7,2], [0,2,2,3,0,3,2], [0,0,2,8,0,0,2], [0,3,1,2,0,1,2], [0,1,2,3,0,1,0], [0,0,0,0,0,1,2]] h,q = hessenberg(a,calc_q=1) assert_array_almost_equal(dot(transp(q),dot(a,q)),h)
def test_simple(self): a = [[-149, -50,-154], [ 537, 180, 546], [ -27, -9, -25]] h1 = [[-149.0000,42.2037,-156.3165], [-537.6783,152.5511,-554.9272], [0,0.0728, 2.4489]] h,q = hessenberg(a,calc_q=1) assert_array_almost_equal(dot(transp(q),dot(a,q)),h) assert_array_almost_equal(h,h1,decimal=4)
def test(self): random = np.random random.seed(_random_seed) size = random.randint(10, 50) matrix = random.rand(size, size) oH = sc.hessenberg(matrix) H = QRAlgorithm.HessenbergReduction(matrix) oVa, _ = np.linalg.eig(matrix) Va, _ = np.linalg.eig(H) assertEqualMatrix(H, oH) assertAbsEqualMatrix(np.sort(oVa), np.sort(Va))
def test(self): random = np.random random.seed(_random_seed) size = random.randint(10, 50) matrix = random.rand(size, size) oH = sc.hessenberg(matrix) H, U = QRAlgorithm.HessenbergReductionWithReflector(matrix) oVa, oVe = np.linalg.eig(matrix) Va, Ve = np.linalg.eig(H) assertAbsEqualMatrix(np.sort(oVa), np.sort(Va)) assertAbsEqualMatrix(H, oH) assertAbsEqualMatrix(oVe, U.dot(Ve))
def qr_algor(A, N, tol): m, n = A.shape S = la.hessenberg(A) for k in range(N): Q, R = la.qr(S) S = R @ Q eigs = [] i = 0
def discrete_lyapunov(A, Q=None): """ Solve the equation :math:`A^T X A + X = -Q`. default Q is set to I :param A: system matrix :type A: np.ndarray | np.matrix | List[List] :param Q: matrix :type Q: np.ndarray | np.matrix :return: the matrix X if there is a solution :rtype: np.ndarray | None """ A = np.array(A) n = A.shape[0] if Q is None: Q = np.eye(n) # matrix size is not greater than 2 x 2, use _mini_dlyap directly if n < 3: return _mini_dlyap(A.T, A, Q) X = np.zeros(A.shape) h, q = hessenberg(A, True) t, z, *_ = schur(h) w = q @ z Q = w.T @ Q @ w partition = _partition_mat(t) for row in partition: for p in row: # ===================================================== # add previous result into Q # e.g. # X11 is already known, then solve X12. # A11^T * X11 * A12 + A11^T * X12 * A22 - X12 = -Q # # let Q' = Q + A11^T * X11 * A12, get the new equation # A11^T * X12 * A22 - X12 = -Q' # ===================================================== Q[p] += _prev_r(X, t)[p] i, j = p X[p] = _mini_dlyap(t[i, i], t[j, j], Q[p]) X = w @ X @ w.T if config['use_numpy_matrix']: return np.mat(X) else: return X
def ss2bode(A, B, C, D, fmin=0.01, fmax=100, tol=1.0e-9, N=200): ''' Compute gain and phase for Bode plot from state space representation of a SISO model tol = threshold for assuming zero gain :return: freqHz, gaindB, phasedeg (Inf and NaN values are excluded) Note: might return empty lists if frequency response is all NaN (poor conditioning). To be improved with matrix balancing and Scipy 0.19 ''' # TO DO: implement balancing for large systems (not available in scipy 0.13.1, see linalg.matrix_balancing) H, Q = hessenberg(A, calc_q=True) H = np.matrix(H) Q = np.matrix(Q) # define frequency range for plot n1 = np.log10(fmin) n2 = np.log10(fmax) freqHz = np.logspace(n1, n2, N) p = 2 * np.pi * freqHz * 1j gaindB = np.zeros(N) phasedeg = np.zeros(N) n = len(A) for i in range(0, len(p)): # h = C * linalg.inv(p[i] * np.eye(n) - A) * B + D # method 1: limited robustness for n>>1 # h = D - (C * Q) * linalg.inv(H - p[i] * np.eye(n)) * (Q.T * B) # method 2: much better x = solve(H - p[i] * np.eye(n), Q.T * B) # method 3: same as 2?? h = D - (C * Q) * x if np.abs(h)[0][0] < tol or np.isnan(h[0][0]): gaindB[i] = -np.inf phasedeg[i] = 0. else: gaindB[i] = 20 * np.log10(np.abs(h)[0][0]) phasedeg[i] = np.angle(h, deg=True)[0][0] phasedeg = np.unwrap(phasedeg * np.pi / 180, discont=np.pi) * 180 / np.pi # restrict output to non-NaN data that would make other function fail i = np.nonzero(np.isfinite(gaindB)) gaindB = gaindB[i] phasedeg = phasedeg[i] freqHz = freqHz[i] i = np.nonzero(np.isfinite(phasedeg)) gaindB = gaindB[i] phasedeg = phasedeg[i] freqHz = freqHz[i] return freqHz, gaindB, phasedeg
def qrm2(): """ Create generator for transformed matrices after applying the QR-Method. Yields: - T: 2D-numpy array. Similar matrix to X. """ # First stage: transform to upper Hessenberg-matrix. T = lin.hessenberg(X) k = 0 # Second stage: perform QR-transformations. while k < 5000: k += 1 Q, R = np.linalg.qr(T) T = R.dot(Q) yield T
def qr_algorithm(A, N=50, tol=1e-12): """Compute the eigenvalues of A via the QR algorithm. Parameters: A ((n,n) ndarray): A square matrix. N (int): The number of iterations to run the QR algorithm. tol (float): The threshold value for determining if a diagonal S_i block is 1x1 or 2x2. Returns: ((n,) ndarray): The eigenvalues of A. """ m, n = np.shape(A) #put A in upper Hessenberg form S = la.hessenberg(A) for k in range(N): #get the QR decomposition of Ak Q, R = la.qr(S) #Recombine Rk and Qk into Ak+1 S = R @ Q #initialize an empty list of eigenvalues eigs = [] i = 0 while i < n: if i == n - 1 or S[i + 1, i] < tol: eigs.append(S[i, i]) else: eig1 = ((S[i, i] + S[i + 1, i + 1]) + cmath.sqrt( (S[i, i] + S[i + 1, i + 1])**2 - 4 * (S[i, i] * S[i + 1, i + 1] - S[i, i + 1] * S[i + 1, i]))) / 2 eig2 = ((S[i, i] + S[i + 1, i + 1]) - cmath.sqrt( (S[i, i] + S[i + 1, i + 1])**2 - 4 * (S[i, i] * S[i + 1, i + 1] - S[i, i + 1] * S[i + 1, i]))) / 2 eigs.append(eig1) eigs.append(eig2) i += 1 #move to next Si i += 1 return eigs
def qrm3(): """ First compute similar matrix in Hessenberg form, then compute the Eigenvalues and Eigenvectors using the accelerated QR-Method. Yields: * T - 2D numpy array of current iteration step. """ # First stage: transform to upper Hessenberg-matrix. T = lin.hessenberg(X) k = 0 n, _ = X.shape # Second stage: perform QR-transformations. while k < 5000: k += 1 Q, R = np.linalg.qr(T - T[n-1, n-1] * np.eye(n)) T = R.dot(Q) + T[n-1, n-1] * np.eye(n) yield T
def calcClosedLoop(self): """ load inputs from linearization and make closed-loop transfer function """ # load selected .jac file res = self.resList.currentText() tlin = self.tLinList.currentText() for i in range(0, len(self.jacFiles)): if self.jacRes[i] == res and self.jacTlin[i] == tlin: file = self.jacFiles[i] data = self.window() dir = os.path.dirname(data.appObject.execDir().decode('utf-8')) [A, B, C, D, x, u, y, t, xvals] = ameloadjNoprint(dir, file) B = B[0] D = D[0] A = np.matrix(A) B = np.matrix(B) C = np.matrix(C) D = np.matrix(D) # retrieve selected input and output tu = self.inputList.currentText() iu = u.index(tu) ty = self.outputList.currentText() iy = y.index(ty) # reshape to SISO model from selected input and output B = B[:, iu] C = C[iy, :] D = np.matrix(D[iy, iu]) # Use Hessenberg decomposition to improve computation robustness for large systems H, Q = hessenberg(A, calc_q=True) H = np.matrix(H) Q = np.matrix(Q) cl = signal.lti(H, Q.H * B, C * Q, D) # go to next step self.CL = cl self.calcOpenLoop()
def qr_algorithm(A, N=50, tol=1e-12): """Compute the eigenvalues of A via the QR algorithm. Inputs: A ((n,n) ndarray): A square matrix. N (int): The number of iterations to run the QR algorithm. tol (float): The threshold value for determining if a diagonal block is 1x1 or 2x2. Returns: ((n, ) ndarray): The eigenvalues of A. """ m,n = A.shape S = la.hessenberg(A) # TODO: introduce shifts. for i in xrange(N): Q,R = la.qr(S) S = np.dot(R,Q) eigs = [] i = 0 # Get the eigenvalues of each S_i. while i < n: if i == n-1: # 1 x 1 block (final diagonal entry). eigs.append(S[i,i]) elif abs(S[i+1,i]) < tol: # 1 x 1 block. eigs.append(S[i,i]) else: # 2 x 2 block. a, b, c, d = S[i:i+2,i:i+2].ravel() # Use the quadratic formula. B = -1*(a+d) C = a*d-b*c D = sqrt(B**2 - 4*C) eigs += [(-B + D)/2., (-B - D)/2.] i += 1 i += 1 return np.sort(eigs)
def qr_solver(A, niter=1000, tol=1e-3): ''' Calculate the eigenvalues of a matrix A using QR iteration. Inputs: A -- real square matrix niter -- number of QR iterations to run tol -- real number. All real numbers with magnitude below we treat as 0 Returns: eigs -- list of real or complex numbers, the eigenvalues of A. Note: this code is far from optimized, but considering that the algorithm itself is inherently limited in robustness, any extra optimization short of chaning the algorithm seems wasted effort. ''' # first calculate the upper hessenberg form of A H = la.hessenberg(A) # perform the QR iterations for i in xrange(niter): Q, R = la.qr(H) H = R.dot(Q) # populate the list of eigenvalues eigs = [] i = 0 while i < H.shape[0]: if i == H.shape[0]-1: #if we are at the last diagonal entry, must be eigenvalue eigs.append(H[i,i]) i += 1 elif abs(H[i+1,i]) < tol: #if subdiagonal zero, diagonal must be e'value eigs.append(H[i,i]) i += 1 else: #subdiagonal nonzero, so find complex e'values of 2x2 block a, b, c, d = H[i:i+2,i:i+2].flatten() T = a + d D = a*d - b*c eigs.append(T/2 + math.sqrt(abs(T**2/4 - D))*1j) eigs.append(T/2 - math.sqrt(abs(T**2/4 - D))*1j) i += 2 return eigs
def hessenberg_realization(G, compute_T=False, form='c', invert=False, output='system'): """ A state transformation is applied in order to get the following form where A is a Hessenberg matrix and B (or C if 'form' is set to 'o' ) is row/col compressed :: [x x x x x|x x] [x x x x x|0 x] [0 x x x x|0 0] [0 0 x x x|0 0] [0 0 0 x x|0 0] [---------|---] [x x x x x|x x] [x x x x x|x x] Parameters ---------- G : State, Transfer, 3-tuple A system representation or the A, B, C matrix triplet of a State realization. Static Gain models are returned unchanged. compute_T : bool, optional If set to True, the array that would bring the system into the desired form will also be returned. Default is False. form : str, optional The switch for selecting between observability and controllability Hessenberg forms. Valid entries are ``c`` and ``o``. invert : bool, optional Select which side the B or C matrix will be compressed. For example, the default case returns the B matrix with (if any) zero rows at the bottom. invert option flips this choice either in B or C matrices depending on the "form" switch. output : str, optional In case only the resulting matrices and not a system representation is needed, this keyword can be used with the value ``'matrices'``. The default is ``'system'``. If 3-tuple is given and 'output' is still 'system' then the feedthrough matrix is taken to be 0. Returns ------- Gh : State, tuple A realization or the matrices are returned depending on the 'output' keyword. T : ndarray If 'compute_T' is set to True, the array for the state transformation is returned. """ if isinstance(G, tuple): a, b, c = G a, b, c, *_ = State.validate_arguments(a, b, c, zeros((c.shape[0], b.shape[1]))) in_is_sys = False else: _check_for_state_or_transfer(G) in_is_sys = True if isinstance(G, Transfer): a, b, c, _ = transfer_to_state(G, output='matrices') else: a, b, c = G.a, G.b, G.c if form == 'o': a, b, c = a.T, c.T, b.T qq, bh = qr(b) ab, cb = qq.T @ a @ qq, c @ qq ah, qh = hessenberg(ab, calc_q=True) ch = cb @ qh if compute_T: T = qq @ qh if invert: ah, bh, ch = fliplr(flipud(ah)), flipud(bh), fliplr(ch) if compute_T: T = flipud(T) if form == 'o': ah, bh, ch = ah.T, ch.T, bh.T if output == 'system': if in_is_sys: Gh = State(ah, bh, ch, dt=G.SamplingPeriod) else: Gh = State(ah, bh, ch) if compute_T: return Gh, T else: return Gh else: if compute_T: return ah, bh, ch, T else: return ah, bh, ch
def get(self, Wt, full=False): r'''Get Arnoldi relation for a deflation subspace choice. :param Wt: the coefficients :math:`\tilde{W}` of the deflation vectors in the basis :math:`[V_n,U]` with ``Wt.shape == (n+d, k)``, i.e., the deflation vectors are :math:`W=[V_n,U]\tilde{W}`. Must fulfill :math:`\tilde{W}^*\tilde{W}=I_k`. :param full: (optional) should the full Arnoldi basis and the full perturbation be returned? Defaults to ``False``. :return: * ``Hh``: the Hessenberg matrix with ``Hh.shape == (n+d-k, n+d-k)``. * ``Rh``: the perturbation core matrix with ``Rh.shape == (l, n+d-k)``. * ``q_norm``: norm :math:`\|q\|_2`. * ``vdiff_norm``: the norm of the difference of the initial vectors :math:`\tilde{v}-\hat{v}`. * ``PWAW_norm``: norm of the projection :math:`P_{\mathcal{W}^\perp,A\mathcal{W}}`. * ``Vh``: (if ``full == True``) the Arnoldi basis with ``Vh.shape == (N, n+d-k)``. * ``F``: (if ``full == True``) the perturbation matrix :math:`F=-Z\hat{R}\hat{V}_n^* - \hat{V}_n\hat{R}^*Z^*`. ''' n = self.n n_ = self.n_ d = self.d k = Wt.shape[1] # get orthonormal basis of Wt and Wt^\perp if k > 0: Wto, _ = scipy.linalg.qr(Wt) Wt = Wto[:, :k] Wto = Wto[:, k:] else: Wto = numpy.eye(Wt.shape[0]) deflated_solver = self._deflated_solver Pt = utils.Projection(self.L.dot(Wt), self.J.T.conj().dot(Wt)) \ .operator_complement() if d > 0: qt = Pt*(numpy.r_[[[deflated_solver.MMlr0_norm]], numpy.zeros((self.n_-1, 1)), numpy.linalg.solve(deflated_solver.E, deflated_solver.UMlr)]) else: qt = Pt*(numpy.r_[[[deflated_solver.MMlr0_norm]], numpy.zeros((self.n_-1, 1))]) q = Wto.T.conj().dot(self.J.dot(qt)) # TODO: q seems to suffer from round-off errors and thus the first # vector in the computed basis may differ from the exact # projected one more than on the level of unit round-off. # rotate closest vector in [V_n,U] to first column Q = utils.House(q) q_norm = Q.xnorm # Arnoldify WtoQ = Q.apply(Wto.T.conj()).T.conj() from scipy.linalg import hessenberg Hh, T = hessenberg( Q.apply(Wto.T.conj().dot(self.J).dot(Pt*(self.L.dot(WtoQ)))), calc_q=True) QT = Q.apply(T) # construct residual Rh = self.N.dot(Pt*self.L.dot(Wto.dot(QT))) # norm of difference between initial vectors vdiff = self.N.dot(qt) vdiff_norm = 0 if vdiff.size == 0 else numpy.linalg.norm(vdiff, 2) # compute norm of projection P_{W^\perp,AW} if k > 0: # compute coefficients of orthonormalized AW in the basis [V,Z] Y = numpy.bmat([[numpy.eye(n_), deflated_solver.B_], [numpy.zeros((d, n_)), deflated_solver.E], [numpy.zeros((self.R12.shape[0], n_)), self.R12]]) YL_Q, _ = scipy.linalg.qr(Y.dot(self.L.dot(Wt)), mode='economic') # compute <W,X> where X is an orthonormal basis of AW WX = Wt.T.conj().dot(numpy.r_[YL_Q[:n, :], YL_Q[n_:n_+d, :]]) PWAW_norm = 1./numpy.min(scipy.linalg.svdvals(WX)) else: PWAW_norm = 1. if full: Vh = numpy.c_[deflated_solver.V[:, :n], deflated_solver.projection.U].dot(Wto.dot(QT)) ip_Minv_B = deflated_solver.linear_system.get_ip_Minv_B() def _apply_F(x): '''Application of the perturbation.''' return -(self.Z.dot(Rh.dot(utils.inner(Vh, x, ip_B=ip_Minv_B))) + Vh.dot(Rh.T.conj().dot(utils.inner(self.Z, x, ip_B=ip_Minv_B))) ) F = utils.LinearOperator((Vh.shape[0], Vh.shape[0]), dtype=deflated_solver.dtype, dot=_apply_F ) return Hh, Rh, q_norm, vdiff_norm, PWAW_norm, Vh, F return Hh, Rh, q_norm, vdiff_norm, PWAW_norm
import numpy as np import scipy as sp import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm import scipy.linalg as linalg a = np.array([ [2,-1,0 ], [-1,2,-1], [0,-1,2 ]]) print linalg.eigvals(a) H,Q = linalg.hessenberg(a, calc_q=True) print H print Q a = H N = 50 result = np.zeros(N) for i in range(N): Q,R = linalg.qr(a) #print "Q" + str(i) + ":" #print Q #print "R" + str(i) + ":" #print R result[i]= R[0,0] a = np.dot(R,Q)
def test_random(self): n = 20 for k in range(2): a = random([n,n]) h,q = hessenberg(a,calc_q=1) assert_array_almost_equal(dot(transp(q),dot(a,q)),h)
leftcounts = totcounts - rightcounts print leftcounts, rightcounts , "\n" #print "leftcount: ", leftcounts, " rightcount: ", rightcounts, "\n\n" if not rightcounts == 0: findeig(A, (a+b)/2, b, rightcounts) if not leftcounts == 0: findeig(A, a, (a+b)/2, leftcounts) def findeigs(A, a = 0, b = 0): if a-b == 0: b = A.shape[0] a = -b totcounter = counteiginterval(A, a, b) findeig(A,a,b,500) n = 500 a, b = 0, 1 eigs = [] A = random.rand(n, n) A = (A + A.T)/2 A = sla.hessenberg(A) findeigs(A) nbrfound = eigs.__len__() shouldfound = sla.eig(A)[0].__len__() print sort(eigs) print sort(sla.eig(A)[0]*-1)*-1 print "Found: ",nbrfound, " Exists: ", shouldfound