@@ -9,10 +9,10 @@ def power_iteration(
9
9
) -> tuple [float , np .ndarray ]:
10
10
"""
11
11
Power Iteration.
12
- Find the largest eignevalue and corresponding eigenvector
12
+ Find the largest eigenvalue and corresponding eigenvector
13
13
of matrix input_matrix given a random vector in the same space.
14
14
Will work so long as vector has component of largest eigenvector.
15
- input_matrix must be symmetric .
15
+ input_matrix must be either real or Hermitian .
16
16
17
17
Input
18
18
input_matrix: input matrix whose largest eigenvalue we will find.
@@ -41,6 +41,12 @@ def power_iteration(
41
41
assert np .shape (input_matrix )[0 ] == np .shape (input_matrix )[1 ]
42
42
# Ensure proper dimensionality.
43
43
assert np .shape (input_matrix )[0 ] == np .shape (vector )[0 ]
44
+ # Ensure inputs are either both complex or both real
45
+ assert np .iscomplexobj (input_matrix ) == np .iscomplexobj (vector )
46
+ is_complex = np .iscomplexobj (input_matrix )
47
+ if is_complex :
48
+ # Ensure complex input_matrix is Hermitian
49
+ assert np .array_equal (input_matrix , input_matrix .conj ().T )
44
50
45
51
# Set convergence to False. Will define convergence when we exceed max_iterations
46
52
# or when we have small changes from one iteration to next.
@@ -57,7 +63,8 @@ def power_iteration(
57
63
vector = w / np .linalg .norm (w )
58
64
# Find rayleigh quotient
59
65
# (faster than usual b/c we know vector is normalized already)
60
- lamda = np .dot (vector .T , np .dot (input_matrix , vector ))
66
+ vectorH = vector .conj ().T if is_complex else vector .T
67
+ lamda = np .dot (vectorH , np .dot (input_matrix , vector ))
61
68
62
69
# Check convergence.
63
70
error = np .abs (lamda - lamda_previous ) / lamda
@@ -68,33 +75,50 @@ def power_iteration(
68
75
69
76
lamda_previous = lamda
70
77
78
+ if is_complex :
79
+ lamda = np .real (lamda )
80
+
71
81
return lamda , vector
72
82
73
83
74
84
def test_power_iteration () -> None :
75
85
"""
76
86
>>> test_power_iteration() # self running tests
77
87
"""
78
- # Our implementation.
79
- input_matrix = np .array ([[41 , 4 , 20 ], [4 , 26 , 30 ], [20 , 30 , 50 ]])
80
- vector = np .array ([41 , 4 , 20 ])
81
- eigen_value , eigen_vector = power_iteration (input_matrix , vector )
82
-
83
- # Numpy implementation.
84
-
85
- # Get eigen values and eigen vectors using built in numpy
86
- # eigh (eigh used for symmetric or hermetian matrices).
87
- eigen_values , eigen_vectors = np .linalg .eigh (input_matrix )
88
- # Last eigen value is the maximum one.
89
- eigen_value_max = eigen_values [- 1 ]
90
- # Last column in this matrix is eigen vector corresponding to largest eigen value.
91
- eigen_vector_max = eigen_vectors [:, - 1 ]
92
-
93
- # Check our implementation and numpy gives close answers.
94
- assert np .abs (eigen_value - eigen_value_max ) <= 1e-6
95
- # Take absolute values element wise of each eigenvector.
96
- # as they are only unique to a minus sign.
97
- assert np .linalg .norm (np .abs (eigen_vector ) - np .abs (eigen_vector_max )) <= 1e-6
88
+ real_input_matrix = np .array ([[41 , 4 , 20 ], [4 , 26 , 30 ], [20 , 30 , 50 ]])
89
+ real_vector = np .array ([41 , 4 , 20 ])
90
+ complex_input_matrix = real_input_matrix .astype (np .complex128 )
91
+ imag_matrix = np .triu (1j * complex_input_matrix , 1 )
92
+ complex_input_matrix += imag_matrix
93
+ complex_input_matrix += - 1 * imag_matrix .T
94
+ complex_vector = np .array ([41 , 4 , 20 ]).astype (np .complex128 )
95
+
96
+ for problem_type in ["real" , "complex" ]:
97
+ if problem_type == "real" :
98
+ input_matrix = real_input_matrix
99
+ vector = real_vector
100
+ elif problem_type == "complex" :
101
+ input_matrix = complex_input_matrix
102
+ vector = complex_vector
103
+
104
+ # Our implementation.
105
+ eigen_value , eigen_vector = power_iteration (input_matrix , vector )
106
+
107
+ # Numpy implementation.
108
+
109
+ # Get eigenvalues and eigenvectors using built-in numpy
110
+ # eigh (eigh used for symmetric or hermetian matrices).
111
+ eigen_values , eigen_vectors = np .linalg .eigh (input_matrix )
112
+ # Last eigenvalue is the maximum one.
113
+ eigen_value_max = eigen_values [- 1 ]
114
+ # Last column in this matrix is eigenvector corresponding to largest eigenvalue.
115
+ eigen_vector_max = eigen_vectors [:, - 1 ]
116
+
117
+ # Check our implementation and numpy gives close answers.
118
+ assert np .abs (eigen_value - eigen_value_max ) <= 1e-6
119
+ # Take absolute values element wise of each eigenvector.
120
+ # as they are only unique to a minus sign.
121
+ assert np .linalg .norm (np .abs (eigen_vector ) - np .abs (eigen_vector_max )) <= 1e-6
98
122
99
123
100
124
if __name__ == "__main__" :
0 commit comments