Calculates the eigenvalues and eigenvectors of the input matrix.
    Returns a tuple of (eigenvalues, eigenvectors, cumulative percentage of
    variance explained). Eigenvalues and eigenvectors are sorted in order of
    eigenvalue magnitude, high to low

def eigen(matrix):
    """ Calculates the eigenvalues and eigenvectors of the input matrix.
    Returns a tuple of (eigenvalues, eigenvectors, cumulative percentage of
    variance explained). Eigenvalues and eigenvectors are sorted in order of
    eigenvalue magnitude, high to low """

    (vals, vecs) = np.linalg.eigh(matrix)
    ind = vals.argsort()[::-1]
    vals = vals[ind]
    vecs = vecs[:, ind]
    vals_ = vals.copy()
    vals_[vals_ < 0] = 0.
    cum_var_exp = np.cumsum(vals_ / vals_.sum())
    return Decomp(matrix.copy(), vals, vecs, cum_var_exp)