pythonarrayssortingnumpyeigenvalue

Sorting eigenvalues and eigenvectors


The function numpy.linalg.eig supports calculating the eigenvalues and eigenvectors of a stack of matrices at once. In my case, I have 500000 2x2 matrices, organised in a 1000x500x2x2 numpy array, and calling numpy.linalg.eig on this returns 1000x500x2 eigenvalues and 1000x500x2 (2-component) eigenvectors. Just what I need. However, I need the eigenvalues and eigenvectors to be sorted. I tried to sort the eigenvalues with

vals, vecs = np.linalg.eig(array)
vals = vals[np.argsort(vals, axis = -1)]

yet this returns an array of shape 1000x500x2x500x2, instead of 1000x500x2, which I would expect. Is there a simple way to fix this, without resorting to looping over the array? And is there a similarly simple way to sort the eigenvectors according to the eigenvalues?

This question has sort of been answered here: Sorted eigenvalues and eigenvectors on a grid but the answer is tailored to a (another) special case, and not very well explained, and I haven't been successful in adapting it to my case. I considered posting a comment to that answer, asking for details, but I am currently at 49 reputation points, and you need 50 to comment.


Solution

  • Solution developed in conjunction with Tor. It will swap columns of the 2x2 matrices depending on "eigenvalue" order (fake eigenvectors generated by np.random).

    import numpy as np
    import itertools
    Nx = 1000
    Ny = 500
    vals = np.random.rand(Nx, Ny, 2)
    vecs = np.random.rand(Nx, Ny, 2, 2)
    sort_order = np.argsort(vals, -1)
    L = np.array(list(itertools.product(range(Nx), range(Ny), range(2))))
    d0 = L[:,0]
    d1 = L[:,1]
    d2 = L[:,2]
    vecsort = vecs[ np.c_[d0, d0], np.c_[d1, d1], np.c_[d2, d2], sort_order[d0, d1] ].reshape(Nx, Ny, 2, 2)
    # vals can be sorted in place using:
    vals.sort(axis=2)