Source code for radtools.magnons.diagonalization
import numpy as np
from numpy.linalg import LinAlgError
__all__ = ["solve_via_colpa"]
class ColpaFailed(Exception):
r"""
Raised when Diagonalization via Colpa fails.
"""
def __init__(self):
self.message = "Diagonalization via Colpa failed."
def __str__(self):
return self.message
[docs]
def solve_via_colpa(D):
r"""
Diagonalize grand-dynamical matrix following the method of Colpa [1]_.
Algorithm itself is described in section 3, Remark 1 of [1]_.
Parameters
----------
D : (2N, 2N) |array_like|_
Grand dynamical matrix. Must be Hermitian and positive-defined.
Returns
-------
E : (2N,) :numpy:`ndarray`
The eigenvalues, each repeated according to its multiplicity.
First N eigenvalues are sorted in descending order.
Last N eigenvalues are sorted in ascending order.
In the case of diagonalization of the magnon Hamiltonian
first N eigenvalues are the same as last N eigenvalues, but
in reversed order.
G : (2N, 2N) :numpy:`ndarray`
Transformation matrix, which change the basis from the original set of bosonic
operators :math:`\boldsymbol{a}_{\boldsymbol{k}}`to the set of
new bosonic operators :math:`\boldsymbol{c}_{\boldsymbol{k}}` which diagonalize
the Hamiltonian which corresponds to the grand-dynamical matrix ``D``:
.. math::
\boldsymbol{c}_{\boldsymbol{k}} = \boldsymbol{G} \boldsymbol{a}_{\boldsymbol{k}}
where (same for :math:`\boldsymbol{c}_{\boldsymbol{k}}`)
.. math::
\boldsymbol{a}_{\boldsymbol{k}} =
\begin{pmatrix}
\boldsymbol{\alpha}_{\boldsymbol{k}} \\
\boldsymbol{\alpha}_{-\boldsymbol{k}}^{\dagger}
\end{pmatrix}
Notes
-----
Let :math:`\boldsymbol{E}` be the diagonal matrix of eigenvalues ``E``.
.. math::
\boldsymbol{E} = (\boldsymbol{G}^{\dagger})^{-1} \boldsymbol{D} \boldsymbol{G}^{-1}
References
----------
.. [1] Colpa, J.H.P., 1978.
Diagonalization of the quadratic boson hamiltonian.
Physica A: Statistical Mechanics and its Applications,
93(3-4), pp.327-353.
"""
D = np.array(D)
N = len(D) // 2
g = np.diag(np.concatenate((np.ones(N), -np.ones(N))))
try:
# In Colpa article decomposition is K^{\dag}K, while numpy gives KK^{\dag}
K = np.conjugate(np.linalg.cholesky(D)).T
except LinAlgError:
raise ColpaFailed
L, U = np.linalg.eig(K @ g @ np.conjugate(K).T)
# Sort with respect to L, in descending order
U = np.concatenate((L[:, None], U.T), axis=1).T
U = U[:, np.argsort(U[0])]
L = U[0, ::-1]
U = U[1:, ::-1]
E = g @ L
G_minus_one = np.linalg.inv(K) @ U @ np.sqrt(np.diag(E))
# Compute G from G^-1 following Colpa, see equation (3.7) for details
G = np.conjugate(G_minus_one).T
G[:N, N:] *= -1
G[N:, :N] *= -1
return E, G