mirror of
https://github.com/vale981/hopsflow
synced 2025-03-05 08:51:37 -05:00
correlation works
This commit is contained in:
parent
87eadc4cd7
commit
96336fc795
1 changed files with 187 additions and 13 deletions
|
@ -5,11 +5,14 @@ This is done analytically for a BCF that is a sum of exponentials.
|
|||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
import util
|
||||
from .util import BCF, expand_t
|
||||
from . import util
|
||||
from .util import BCF
|
||||
import numpy as np
|
||||
from numpy.typing import NDArray
|
||||
from numpy.polynomial import Polynomial
|
||||
from typing import Union, Optional
|
||||
from itertools import product
|
||||
from numba import jit
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -219,12 +222,8 @@ class Propagator:
|
|||
self.params = sys
|
||||
self._roots, self._res = calculate_coefficients(sys)
|
||||
|
||||
@expand_t
|
||||
def __call__(self, t: NDArray[np.float64]) -> np.ndarray:
|
||||
"""Get the propagator as array of shape ``(time, 4, 4)``."""
|
||||
|
||||
mat = self._res
|
||||
residual_matrix = np.array(
|
||||
self._residual_matrix = np.array(
|
||||
[
|
||||
[mat[0], mat[1], mat[2], mat[3]],
|
||||
[mat[4], mat[0], mat[5], mat[6]],
|
||||
|
@ -233,12 +232,187 @@ class Propagator:
|
|||
]
|
||||
)
|
||||
|
||||
def propagator(self, t: Union[NDArray[np.float64], float]) -> np.ndarray:
|
||||
"""
|
||||
Get the propagator as array of shape ``(time, 4, 4)`` or
|
||||
``(4, 4)`` if ``t`` is a float.
|
||||
"""
|
||||
t = np.asarray(t)
|
||||
was_float = False
|
||||
if t.shape == tuple():
|
||||
t = np.array([t])
|
||||
was_float = True
|
||||
|
||||
res = np.sum(
|
||||
self._residual_matrix[None, :, :, :]
|
||||
* np.exp(self._roots[None, :] * t[:, None])[:, None, None, :],
|
||||
axis=3,
|
||||
).real
|
||||
|
||||
return res[0] if was_float else res
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.propagator(*args, **kwargs)
|
||||
|
||||
def inv(self, t: float) -> np.ndarray:
|
||||
"""Get the inverse of the propagator matrix at time ``t``."""
|
||||
|
||||
return np.linalg.inv(self.__call__(t))
|
||||
|
||||
|
||||
class CorrelationMatrix(Propagator):
|
||||
def __init__(
|
||||
self,
|
||||
sys: SystemParams,
|
||||
initial_corr: np.ndarray,
|
||||
αs: tuple[Optional[BCF], Optional[BCF]] = (None, None),
|
||||
):
|
||||
super().__init__(sys)
|
||||
|
||||
self.G = self._residual_matrix
|
||||
self.Ge = -self._roots
|
||||
|
||||
α = []
|
||||
αe = []
|
||||
|
||||
for i, bcf in enumerate(αs):
|
||||
if bcf:
|
||||
α.append(bcf.factors)
|
||||
αe.append(bcf.exponents)
|
||||
else:
|
||||
α.append(self.params.G[i])
|
||||
αe.append(self.params.W[i])
|
||||
|
||||
self.αc = np.array(list(map(np.conj, α)), dtype=object)
|
||||
self.αce = np.array(list(map(np.conj, αe)), dtype=object)
|
||||
self.α = np.array(α, dtype=object)
|
||||
self.αe = np.array(αe, dtype=object)
|
||||
self.initial_corr = initial_corr
|
||||
|
||||
@jit
|
||||
def __call__(
|
||||
self,
|
||||
t: np.ndarray,
|
||||
s: Optional[np.ndarray] = None,
|
||||
) -> NDArray[np.complex128]:
|
||||
r"""Caluclate the corellation matrix :math:`\langle x_i(t)
|
||||
x_j(s)\rangle` of the system.
|
||||
|
||||
:param t: The first time point.
|
||||
:param s: The second timepoint.
|
||||
:param αs: The (finite temparature) bath correlation
|
||||
functions. If they're :any:`None` they're chosen to be
|
||||
the zero temperature BCF.
|
||||
:param initial_corr: The initial correlation matrix
|
||||
:math:`\langle x_i[] x_j\rangle`.
|
||||
"""
|
||||
|
||||
s = s or t
|
||||
|
||||
G = self.G[None, :, :, :]
|
||||
Ge = self.Ge
|
||||
αc = self.αc
|
||||
αce = self.αce
|
||||
α = self.α
|
||||
αe = self.αe
|
||||
initial_corr = self.initial_corr
|
||||
|
||||
if (s > t).any():
|
||||
raise ValueError("`s` must be smaller than or equal to `t`")
|
||||
|
||||
Gt = self.propagator(t)
|
||||
Gs = self.propagator(s)
|
||||
|
||||
result = np.einsum("tik,tjl,kl->tij", Gt, Gs, initial_corr)
|
||||
# (Gt @ initial_corr[None, :, :]) @ Gs.T
|
||||
|
||||
for l in range(len(α)):
|
||||
for i, j, m, n, g in product(
|
||||
range(G.shape[0]),
|
||||
range(G.shape[0]),
|
||||
range(Ge.shape[0]),
|
||||
range(Ge.shape[0]),
|
||||
range(len(α[l])),
|
||||
):
|
||||
# straight from mathematica
|
||||
|
||||
result[:, i, j] += (
|
||||
G[:, i, l, m]
|
||||
* G[:, j, l, n]
|
||||
* (
|
||||
(
|
||||
αc[l, g]
|
||||
* (
|
||||
(-np.exp(s * Ge[n]) + np.exp(s * αce[l, g])) * Ge[m]
|
||||
- np.exp(s * Ge[n]) * Ge[n]
|
||||
+ np.exp(s * (Ge[m] + Ge[n] + αce[l, g]))
|
||||
* (Ge[n] - αce[l, g])
|
||||
+ np.exp(s * αce[l, g]) * αce[l, g]
|
||||
)
|
||||
)
|
||||
/ (
|
||||
np.exp(s * (Ge[n] + αce[l, g]))
|
||||
* (Ge[n] - αce[l, g])
|
||||
* (Ge[m] + αce[l, g])
|
||||
)
|
||||
+ (
|
||||
np.exp(-(s * Ge[n]) - t * αe[l, g])
|
||||
* α[l, g]
|
||||
* (
|
||||
-(
|
||||
np.exp(t * Ge[m])
|
||||
* (-1 + np.exp(s * (Ge[n] + αe[l, g])))
|
||||
* Ge[m]
|
||||
)
|
||||
+ (
|
||||
np.exp(t * Ge[m])
|
||||
- np.exp(t * αe[l, g])
|
||||
+ np.exp(s * (Ge[m] + Ge[n]) + t * αe[l, g])
|
||||
- np.exp(t * Ge[m] + s * (Ge[n] + αe[l, g]))
|
||||
)
|
||||
* Ge[n]
|
||||
+ np.exp(t * αe[l, g])
|
||||
* (-1 + np.exp(s * (Ge[m] + Ge[n])))
|
||||
* αe[l, g]
|
||||
)
|
||||
)
|
||||
/ ((-Ge[m] + αe[l, g]) * (Ge[n] + αe[l, g]))
|
||||
)
|
||||
) / (np.exp(t * Ge[m]) * (Ge[m] + Ge[n]))
|
||||
|
||||
return result
|
||||
|
||||
def system_energy(self, t: np.ndarray) -> float:
|
||||
corr = np.real(np.diagonal(self.__call__(t), axis1=1, axis2=2))
|
||||
|
||||
Ω = self.params.Ω
|
||||
Λ = self.params.Λ
|
||||
γ = self.params.γ
|
||||
|
||||
return (
|
||||
np.sum(
|
||||
residual_matrix * np.exp(self._roots * t)[None, None, :], axis=2
|
||||
).real
|
||||
* 2
|
||||
1
|
||||
/ 4
|
||||
* (
|
||||
Ω * corr[:, 0] # type: ignore
|
||||
+ (Ω + γ) * corr[:, 1] # type: ignore
|
||||
+ Λ * corr[:, 2] # type: ignore
|
||||
+ (Λ + γ) * corr[:, 3] # type: ignore
|
||||
)
|
||||
)
|
||||
|
||||
def inv(self, t) -> np.ndarray:
|
||||
return np.linalg.inv(self.__call__(t))
|
||||
|
||||
def initial_correlation_pure_osci(n: int, m: int):
|
||||
r"""
|
||||
Initial correlation matrix :math:`\langle x_i[] x_j\rangle` for
|
||||
two HO in product eigenstates with labels ``n`` and ``m``.
|
||||
"""
|
||||
corr = np.diag(
|
||||
np.array([1 + 2 * n, 1 + 2 * n, 1 + 2 * m, 1 + 2 * m], dtype=np.complex128)
|
||||
)
|
||||
|
||||
corr[0, 1] = 1j
|
||||
corr[1, 0] = -1j
|
||||
corr[2, 3] = 1j
|
||||
corr[3, 2] = -1j
|
||||
|
||||
return corr
|
||||
|
|
Loading…
Add table
Reference in a new issue