@@ -119,3 +119,110 @@ def power_method_numba(A):
119
119
float: The approximated dominant eigenvalue of the matrix `A`.
120
120
"""
121
121
return power_method_numba_helper (A )
122
+
123
+
124
+ def Lanczos_PRO (A , q , m = None , toll = np .sqrt (np .finfo (float ).eps )):
125
+ """
126
+ Perform the Lanczos algorithm for symmetric matrices.
127
+
128
+ This function computes an orthogonal matrix Q and tridiagonal matrix T such that A ≈ Q * T * Q.T,
129
+ where A is a symmetric matrix. The algorithm is useful for finding a few eigenvalues and eigenvectors
130
+ of large symmetric matrices.
131
+
132
+ Args:
133
+ A (np.ndarray): A symmetric square matrix of size n x n.
134
+ q (np.ndarray): Initial vector of size n.
135
+ m (int, optional): Number of eigenvalues to compute. Must be less than or equal to n.
136
+ If None, defaults to the size of A.
137
+ toll (float, optional): Tolerance for orthogonality checks (default is sqrt(machine epsilon)).
138
+
139
+ Returns:
140
+ tuple: A tuple (Q, alpha, beta) where:
141
+ - Q (np.ndarray): Orthogonal matrix of size n x m.
142
+ - alpha (np.ndarray): Vector of size m containing the diagonal elements of the tridiagonal matrix.
143
+ - beta (np.ndarray): Vector of size m-1 containing the off-diagonal elements of the tridiagonal matrix.
144
+
145
+ Raises:
146
+ ValueError: If the input matrix A is not square or if m is greater than the size of A.
147
+ """
148
+ q = q / np .linalg .norm (q )
149
+ Q = np .array ([q ])
150
+ r = A @ q
151
+ alpha = []
152
+ beta = []
153
+ alpha .append (q @ r )
154
+ r = r - alpha [0 ] * q
155
+ beta .append (np .linalg .norm (r ))
156
+ count = 0
157
+ for j in range (1 , m ):
158
+ q = r / beta [j - 1 ]
159
+ for q_basis in Q [:- 1 ]:
160
+ if np .abs (q @ q_basis ) > toll :
161
+ for q_bbasis in Q [:- 1 ]:
162
+ q = q - (q @ q_bbasis ) * q_bbasis
163
+ count += 1
164
+ break
165
+ q = q / np .linalg .norm (q )
166
+ Q = np .vstack ((Q , q ))
167
+ r = A @ q - beta [j - 1 ] * Q [j - 1 ]
168
+ alpha .append (q @ r )
169
+ r = r - alpha [j ] * q
170
+ beta .append (np .linalg .norm (r ))
171
+
172
+ if np .abs (beta [j ]) < 1e-15 :
173
+ return Q , alpha , beta [:- 1 ]
174
+ return Q , alpha , beta [:- 1 ]
175
+
176
+
177
+
178
+ def QR_method (A_copy , tol = 1e-10 , max_iter = 100 ):
179
+ """
180
+ Compute the eigenvalues of a tridiagonal matrix using the QR algorithm.
181
+
182
+ This function uses the QR decomposition method to iteratively compute the eigenvalues of a given tridiagonal matrix.
183
+ The QR algorithm is an iterative method that computes the eigenvalues of a matrix by decomposing it into a product
184
+ of an orthogonal matrix Q and an upper triangular matrix R, and then updating the matrix as the product of R and Q.
185
+
186
+ Args:
187
+ A_copy (np.ndarray): Atridiagonal matrix whose eigenvalues are to be computed.
188
+ tol (float, optional): Tolerance for convergence based on the off-diagonal elements (default is 1e-10).
189
+ max_iter (int, optional): Maximum number of iterations to perform (default is 100).
190
+
191
+ Returns:
192
+ tuple: A tuple (eigenvalues, Q) where:
193
+ - eigenvalues (np.ndarray): An array containing the eigenvalues of the matrix `A_copy`.
194
+ - Q (np.ndarray): The orthogonal matrix Q from the final QR decomposition.
195
+
196
+ Raises:
197
+ ValueError: If the input matrix A_copy is not square.
198
+ """
199
+
200
+ A = A_copy .copy ()
201
+ T = A .copy ()
202
+ A = np .array (A )
203
+ iter = 0
204
+
205
+ while np .linalg .norm (np .diag (A , - 1 ), np .inf ) > tol and iter < max_iter :
206
+ Matrix_trigonometry = np .array ([])
207
+ QQ , RR = np .linalg .qr (T )
208
+ T = RR @QQ
209
+ for i in range (A .shape [0 ]- 1 ):
210
+ c = A [i , i ]/ np .sqrt (A [i , i ]** 2 + A [i + 1 , i ]** 2 )
211
+ s = - A [i + 1 , i ]/ np .sqrt (A [i , i ]** 2 + A [i + 1 , i ]** 2 )
212
+ Matrix_trigonometry = np .vstack ((Matrix_trigonometry , [c , s ])) if Matrix_trigonometry .size else np .array ([[c , s ]])
213
+
214
+ R = np .array ([[c , - s ], [s , c ]])
215
+ A [i :i + 2 , i :i + 3 ]= R @A [i :i + 2 , i :i + 3 ]
216
+ A [i + 1 , i ]= 0
217
+ Q = np .eye (A .shape [0 ])
218
+ i = 0
219
+ Q [0 :2 , 0 :2 ]= np .array ([[Matrix_trigonometry [i , 0 ], Matrix_trigonometry [i , 1 ]], [- Matrix_trigonometry [i , 1 ], Matrix_trigonometry [i , 0 ]]])
220
+ for i in range (1 , A .shape [0 ]- 1 ):
221
+ R = np .eye (A .shape [0 ])
222
+ R [i : i + 2 , i :i + 2 ]= np .array ([[Matrix_trigonometry [i , 0 ], Matrix_trigonometry [i , 1 ]], [- Matrix_trigonometry [i , 1 ], Matrix_trigonometry [i , 0 ]]])
223
+ Q = Q @R
224
+ A = A @Q
225
+ iter += 1
226
+
227
+
228
+ return np .diag (A ), Q
0 commit comments