Eigenvalue level repulsion
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$).
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()