Search code examples
pythonnumpyeigenvalueeigenvector

Why is numpy.dot() throwing a ValueError: shapes not aligned?


I want to write a program that finds the eigenvectors and eigenvalues of a Hermitian matrix by iterating over a guess (Rayleigh quotient iteration). I have a test matrix that I know the eigenvectors and eigenvalues of, however when I run my code I receive

ValueError: shapes (3,1) and (3,1) not aligned: 1 (dim 1) != 3 (dim 0)

By splitting each numerator and denominator into separate variables I've traced the problem to the line:

nm=np.dot(np.conj(b1),np.dot(A,b1))

My code:

import numpy as np
import numpy.linalg as npl

def eigen(A,mu,b,err):

    mu0=mu
    mu1=mu+10*err

    while mu1-mu > err:

        n=np.dot((npl.inv(A-mu*np.identity(np.shape(A)[0]))),b)
        d=npl.norm(np.dot((npl.inv(A-(mu*np.identity(np.shape(A)[0])))),b))

        b1=n/d
        b=b1

        nm=np.dot(np.conj(b1),np.dot(A,b1))
        dm=np.dot(np.conj(b1),b1)

        mu1=nm/dm
        mu=mu1

    return(mu,b)

A=np.array([[1,2,3],[1,2,1],[3,2,1]])
mu=4
b=np.array([[1],[2],[1]])
err=0.1

eigen(A,mu,b,err) 

I believe the dimensions of the variables being input into the np.dot() function are wrong, but I cannot find where. Everything is split up and renamed as part of my debugging, I know it looks very difficult to read.


Solution

  • The mathematical issue is with matrix multiplication of shapes (3,1) and (3,1). That's essentially two vectors. Maybe you wanted to use the transposed matrix to do this?

    nm = np.dot(np.conj(b1).T, np.dot(A, b1))
    dm = np.dot(np.conj(b1).T, b1)
    

    Have a look at the documentation of np.dot to see what arguments are acceptable.

    If both a and b are 1-D arrays, it is inner product of vectors (...)

    If both a and b are 2-D arrays, it is matrix multiplication (...)

    The variables you're using are of shape (3, 1) and therefore 2-D arrays.

    Also, this means, alternatively, instead of transposing the first matrix, you could use a flattened view of the array. This way, it's shape (3,) and a 1-D array and you'll get the inner product:

    nm = np.dot(np.conj(b1).ravel(), np.dot(A, b1).ravel())
    dm = np.dot(np.conj(b1).ravel(), b1.ravel())