Source code for fermifab.util
import numpy as np
from scipy.sparse import issparse
from .fermistate import FermiState
from .fermiop import FermiOp
__all__ = ['crand', 'norm', 'kron', 'trace', 'trace_prod', 'matrix_power', 'eig', 'comprise_config']
def crand(*args):
return 0.5 - np.random.rand(*args) + 1j*(0.5 - np.random.rand(*args))
[docs]def norm(x, ord=None):
"""Compute the norm of a `FermiState` or `FermiOp`."""
return np.linalg.norm(x.data, ord)
[docs]def kron(x, y):
"""Compute the Kronecker product of two Fermi operators."""
if type(x) == type(y) == FermiOp:
return FermiOp([x.orbs, y.orbs],
[x.pFrom, y.pFrom],
[x.pTo, y.pTo],
np.kron(x.data, y.data))
elif type(x) == type(y) == FermiState:
return FermiState([x.orbs, y.orbs],
[x.N, y.N],
np.kron(x.data, y.data))
else:
raise TypeError("x and y must be both FermiOp or FermiState.")
[docs]def matrix_power(op, n):
"""Compute the `n`-th matrix power of a Fermi operator."""
return FermiOp(op.orbs, op.pFrom, op.pTo, data=np.linalg.matrix_power(op.data, n))
[docs]def eig(op):
"""Eigenvalues and eigenstates of Fermi operators"""
assert type(op) == FermiOp
D, U = np.linalg.eig(op.data)
return D, FermiOp(op.orbs, op.pFrom, op.pTo, U)
[docs]def trace(op):
"""Compute the trace of a `FermiOp`."""
return np.trace(op.data)
[docs]def trace_prod(A, B):
"""Calculate trace(A*B) efficiently."""
if issparse(A) or issparse(B):
return np.trace(A @ B)
else:
return sum(A[j,:] @ B[:,j] for j in range(A.shape[0]))
[docs]def comprise_config(orbs1, orbs2, N1, N2):
"""Comprise configurations."""
assert (sum(orbs1) == sum(orbs2)) & (sum(N1) == sum(N2))
assert np.all(orbs1 > 0) & np.all(orbs2>0)
# cumulative number of orbitals
cumorbs1 = np.cumsum(orbs1)
cumorbs2 = np.cumsum(orbs2)
#cumulative particle numbers
n1 = np.cumsum(N1)
n2 = np.cumsum(N2)
# merge tables
m1 = np.ones_like(cumorbs1, dtype=bool)
m2 = np.ones_like(cumorbs2, dtype=bool)
orbs = [orbs1[0]]
N = [N1[0]]
j1 = 0
j2 = 0
while j1 < len(cumorbs1)-1:
if cumorbs1[j1] < cumorbs2[j2]:
orbs[-1] += orbs1[j1+1]
N[-1] += N1[j1+1]
j1 += 1
elif cumorbs2[j2] < cumorbs1[j1]:
j2 += 1
else:
if n1[j1] == n2[j2]:
# both mode and particle numbers match
m1[j1] = False
m2[j2] = False
orbs.append(orbs1[j1+1])
N.append(N1[j1+1])
else:
orbs[-1] += orbs1[j1+1]
N[-1] += N1[j1+1]
j1 += 1
j2 += 1
assert (sum(orbs) == cumorbs1[-1]) & (sum(N) == n1[-1])
m1 = m1[:-1]
m2 = m2[:-1]
return m1, m2, orbs, N