Power Iteration
Implement the power iteration method to find the dominant eigenvector of a matrix. This task involves understanding the underlying concept of eigenvalues and eigenvectors, which are crucial in linear algebra and have numerous applications in computer vision and machine learning.
The power iteration method is an iterative algorithm that finds the eigenvector corresponding to the largest eigenvalue of a matrix A. The process involves starting with a random vector v0 and iteratively updating it using the matrix A. The key idea is to repeatedly apply the matrix A to the current vector and normalize the result.
Here are the general steps:
- Initialize a random vector v0
- Iterate: update the vector using the matrix A and normalize the result
- Repeat until convergence
This technique is widely used in principal component analysis (PCA).
Example:
power_iteration([[2, 0], [0, 1]], [1, 1], 10)
[1.0, 0.0]
Converges to eigenvector [1, 0] for eigenvalue 2
Constraints:
- A is a square matrix (n×n) where 2 ≤ n ≤ 10
- Perform exactly the specified number of iterations
- Normalize the vector after each iteration
- Return the final vector rounded to 4 decimal places
Power iteration is an extremely simple iterative method to approximate the eigenvector associated with the largest eigenvalue (the dominant eigenvector) of a matrix. The key idea: if you repeatedly multiply a vector by a matrix A, the component along the eigenvector with the largest eigenvalue λmax gets amplified the most, so the direction of the vector converges to that eigenvector (after normalization each step). This works well for large, sparse matrices where full eigen-decomposition (e.g., via SVD or QR) is too expensive.
In applications like PageRank and PCA, we care primarily about this dominant eigenvector: PageRank’s ranking vector is the dominant eigenvector of a stochastic matrix; in PCA, the first principal component is the dominant eigenvector of the covariance matrix. Power iteration is attractive here because it uses only matrix–vector products and normalizations, which are easy to implement and scale to large dimensions.
1. Background Knowledge (concepts & theory)
- Eigenvalues/eigenvectors For a square matrix A∈Rn×n, a nonzero vector v is an eigenvector if:
for some scalar λ, the eigenvalue. Geometrically, applying A to v only scales it (by λ), not change its direction.
-
Dominant eigenvalue/eigenvector Let the eigenvalues be λ1,…,\lambdan ordered so that ∣\lambda1∣>∣\lambda2∣≥⋯≥∣\lambdan∣.
-
λ1 is the dominant eigenvalue.
-
Its eigenvector v1 is the dominant eigenvector. Power iteration converges to v1 under mild conditions (e.g., ∣\lambda1∣>∣\lambda2∣ and the starting vector has a nonzero component in direction v1).
-
Why normalization? If you repeatedly compute xk+1=Axk, the norm ∥xk∥ tends to blow up or decay (depending on ∣\lambda1∣). Normalizing:
keeps vectors on the unit sphere so the sequence converges in direction to the dominant eigenvector.
2. Algorithm / Approach
The power iteration pattern is:
- Pick an initial nonzero vector v0 (often random).
- Repeat:
- Multiply by matrix: w=Avk
- Normalize: vk+1=∥w∥w
- Stop when convergence: e.g., ∥vk+1−vk∥ is below a tolerance or max iterations reached.
- (Optionally) approximate the dominant eigenvalue with the Rayleigh quotient:
This is a simple fixed-point iteration: you are iterating a function f(v)=∥Av∥Av until it stops changing much.
3. Step-by-Step Strategy (for implementation)
Assuming you have:
- Matrix A as an n×n array
- Parameters: max_iters, tol (tolerance)
A typical strategy:
- Initialize vector
- Create a random vector:
v = np.random.randn(n)
v = v / np.linalg.norm(v)
- Ensure it is not the zero vector.
- Main iteration loop
for k in range(max_iters):
# 1) Matrix-vector product
w = A @ v # or A.dot(v)
# 2) Compute norm (e.g., L2)
norm_w = np.linalg.norm(w)
# 3) Normalize
v_new = w / norm_w
# 4) Check convergence
if np.linalg.norm(v_new - v) < tol:
v = v_new
break
v = v_new
- Return the dominant eigenvector
- v is your approximate dominant eigenvector.
- Optional: estimate eigenvalue
lambda_est = float(v.T @ (A @ v))
When coding for a platform problem, you’ll wrap this logic in a function and use the platform’s provided matrix/vector types.
4. Common Pitfalls
-
Not normalizing each step Without normalization, the vector may overflow or underflow numerically; convergence in direction is then unstable.
-
Bad stopping criteria
-
Using only k == max_iters without checking convergence can waste iterations or return a poor approximation.
-
A robust choice is ||v_{k+1} - v_k|| < tol or ||A v_k - λ v_k|| < tol.
-
Starting vector issues
-
If the initial vector is orthogonal to the dominant eigenvector, convergence fails. With a random vector, this almost never happens in practice, but avoid starting with the zero vector or a very special structure.
-
Non-dominant or close eigenvalues
-
If ∣\lambda1∣ is close to ∣\lambda2∣, convergence can be slow.
-
If there are multiple eigenvalues with the same largest magnitude, the method may converge to some vector in the subspace they span, not a unique eigenvector.
-
Non-symmetric matrices
-
Power iteration still works for general matrices, but:
-
The dominant eigenvalue might be complex.
-
Implementation with real arithmetic usually assumes A has a real dominant eigenvalue/eigenvector.
-
Numerical stability in norm
-
Use a stable norm function (e.g., np.linalg.norm); don’t manually compute sqrt(sum(x[i]**2)) if you can avoid it.
5. Time & Space Complexity
Let n be the dimension of the matrix (i.e., A is n×n) and let T be the number of iterations until convergence.
-
Time complexity
-
Each iteration does a matrix–vector product Av.
-
Dense A: O(n2) per iteration.
-
Sparse A: O(\text{nnz}(A)) per iteration, where nnz is number of nonzeros.
-
Total: O(T⋅n2) for dense, or O(T⋅\text{nnz}(A)) for sparse.
-
Space complexity
-
You store:
-
The matrix A: O(n2) for dense, or O(\text{nnz}(A)) for sparse.
-
A few vectors of size n: O(n).
-
Additional overhead is constant, so asymptotically it is dominated by the storage of A.
This complexity profile explains why power iteration is popular in large-scale ML/vision tasks: it uses simple, repeated matrix–vector products that can leverage sparsity and GPU acceleration.