GID

Eigenvalue level repulsion

· Georgios Is. Detorakis · 2 minutes read

Imaging we have two matrices ${\bf A}, {\bf B}$ $\in \mathbb{R}^n$, that are both symmetric. Then, we know that both matrices have $n$ eigenvalues (multiplicity). Let’s start now, gradually morphing ${\bf A}$ to ${\bf B}$ using the following formula

$$ {\bf A}[t] = (1 - t) {\bf A} + t {\bf B}, $$

where $t \in [0, 1]$. What will happen is that matrix ${\bf A}$ will have multiple eigenvalues with probability zero, given we have chosen the matrices properly from the set of all real symmetric matrices. In other words, there will be no time $t$ when matrix ${\bf A}$ won’t have $n$ eigenvalues. We can see an example in Figure $1$ below.

Figure 1. Eigenvalue level repulsion. Notice that as we move from $t=0$ to $t=1$ the eigenvalues of matrix ${\bf A}$ morph to those of ${\bf B}$ and at any instance matrix ${\bf A}$ has $10$ eigenvalues (see the dimension of the matrix ${\bf A}$ in the code snippet below, which is $10$).

Figure 1. Eigenvalue level repulsion. Notice that as we move from $t=0$ to $t=1$ the eigenvalues of matrix ${\bf A}$ morph to those of ${\bf B}$ and at any instance matrix ${\bf A}$ has $10$ eigenvalues (see the dimension of the matrix ${\bf A}$ in the code snippet below, which is $10$).

The Python code below shows how one can compute the eigenvalue level repulsion.

import numpy as np
import matplotlib.pylab as plt
import matplotlib.style as style

style.use('tableau-colorblind10')

params = {'font.size': 14,
          }
plt.rcParams.update(params)


def keig(A, k):
    # Compute the eigenvalues of a matrix, sort them and then choose the k fisrt of them
    kth_eig = np.sort(np.linalg.eigvals(A))[k]
    return kth_eig


if __name__ == '__main__':
    np.random.seed(1)

    # Randomly select two matrices A and B and make sure they are symmetric
    n, nnodes = 10, 50
    A = np.random.randn(n, n)
    A = A + A.conj().T
    B = np.random.randn(n, n)
    B = B + B.conj().T

    # Define the discretization of interval [0, 1]
    t = np.linspace(0, 1, nnodes)

    # Run over t and compute the eigenvalues
    res = []
    for k in range(n):
        tmp_mat = []
        for i in range(nnodes):
            tmp_mat.append(keig((1 - t[i]) * A + t[i] * B, k))
        res.append(tmp_mat)

    # Plot the results
    min_ = int(min(min(res)))
    max_ = int(max(max(res)))

    fig = plt.figure(figsize=(13, 6))
    ax = fig.add_subplot(111)
    for i in range(n):
        # label numbering should start from 1 not 0   
        ax.plot(t, res[i], '-x', label="Eigenvalue "+str(i+1))
    ax.set_xlabel(r"$t$", fontsize=20, weight="bold")
    ax.set_ylabel(r"$\lambda_{A(t)}$", fontsize=20, weight="bold")
    ax.set_xticks([i/10 for i in range(11)])
    ticks = ax.get_xticks()
    ax.set_xticklabels(ticks, fontsize=14, weight='bold')
    ax.set_yticks([i for i in range(min_, max_)])
    ticks = ax.get_yticks()
    ax.set_yticklabels(ticks, fontsize=14, weight='bold')

    pos = ax.get_position()
    ax.set_position([pos.x0, pos.y0, pos.width * 0.9, pos.height])
    ax.legend(loc='center right', bbox_to_anchor=(1.25, 0.5))

    ax.set_title("Eigenvalue Repulsion")
    plt.show()