Пример #1
0
def lindbladian(l, rho):
    """
    lindblad superoperator: l rho l^\dag - 1/2 * {l^\dag l, rho}
    l is the operator corresponding to the disired physical process
    e.g. l = a, for the cavity decay and
    l = sm for polarization decay
    """
    return l.dot(rho.dot(dag(l))) - 0.5 * anticomm(dag(l).dot(l), rho)
Пример #2
0
    def eigenstates(self, k=None):

        if self.L is None:
            # raise ValueError('L is None. Call liouvillian to construct L first.')
            L = self.liouvillian()
        else:
            L = self.L

        N = L.shape[-1]

        if k is None:

            w, vl, vr = scipy.linalg.eig(L.toarray(), left=True, \
                                              right=True)
            self.eigvals = w
            self.left_eigvecs = vl
            self.right_eigvecs = vr
            # self.norm = [np.vdot(vl[:,n], vr[:,n]) for n in range(self.dim)]

            self.norm = np.diagonal(cdot(vl, vr)).real

        elif k < N - 1:
            # right eigenvectors of L
            evals1, U1 = eigs(L, k=k, which='LR')
            evals1, U1 = sort(evals1, U1)

            # left
            evals2, U2 = eigs(dag(L), k=k, which='LR')
            evals2, U2 = sort(evals2, U2)

        else:
            raise ValueError('k should be < the size of the matrix.')

        return w, vr, vl
Пример #3
0
    def rdm(self, psi, which='A'):
        """
        compute the reduced density matrix of A/B from a pure state

        Parameters
        ----------
        psi: array
            pure state
        which: str
            indicator of which rdm A or B. Default 'A'.

        Returns
        -------

        """
        na = self.A.dim
        nb = self.B.dim
        psi_reshaped = psi.reshape((na, nb))
        if which == 'A':

            rdm = psi_reshaped @ dag(psi_reshaped)
            return rdm

        elif which == 'B':
            rdm = psi_reshaped.T @ psi_reshaped.conj()
            return rdm
        else:
            raise ValueError('which option can only be A or B.')
Пример #4
0
def rdm(f, dx=1, dy=1, which='x'):
    '''
    Compute the reduced density matrix by tracing out the other dof for a 2D wavefunction

    Parameters
    ----------
    f : 2D array
        2D wavefunction
    dx : float, optional
        DESCRIPTION. The default is 1.
    dy : float, optional
        DESCRIPTION. The default is 1.
    which: str
        indicator which rdm is required. Default is 'x'.

    Returns
    -------
    rho1 : TYPE
        Reduced density matrix

    '''
    if which == 'x':
        rho = f.dot(dag(f)) * dy
    elif which == 'y':
        rho = f.T.dot(np.conj(f)) * dx
    else:
        raise ValueError('The argument which can only be x or y.')
    return rho
Пример #5
0
    def correlation_3p_1t(self, psi0, oplist, dt, Nt):
        """
        <AB(t)C>

        Parameters
        ----------
        psi0
        oplist
        dt
        Nt

        Returns
        -------

        """
        H = self.H
        a_op, b_op, c_op = oplist

        corr_vec = np.zeros(Nt, dtype=complex)

        psi_ket = _quantum_dynamics(H, c_op @ psi0, dt=dt, Nt=Nt).psilist
        psi_bra = _quantum_dynamics(H, dag(a_op) @ psi0, dt=dt, Nt=Nt).psilist

        for j in range(Nt):
            corr_vec[j] = np.vdot(psi_bra[j], b_op @ psi_ket[j])

        return corr_vec
Пример #6
0
def linear_absorption(omegas, ham, dip):
    """
    Note that the eigenvectors of the liouvillian L and L^\dag have to 
    be ordered in parallel!

    Parameters
    ----------
    omegas : TYPE
        DESCRIPTION.
    ham : TYPE
        DESCRIPTION.
    dip : TYPE
        DESCRIPTION.
    rho0 : 2d array
        initial density matrix 
    c_ops : TYPE, optional
        DESCRIPTION. The default is [].
    ntrans : int, optional
        Number of transitions to be computed. The default is 1.

    Returns
    -------
    signal : TYPE
        DESCRIPTION.

    """

    ntrans = np.size(ham, 0)

    eigvals1, U1 = eig(ham)
    eigvals1, U1 = sort(eigvals1, U1)

    eigvals2, U2 = eig(dag(ham))
    eigvals2, U2 = sort(eigvals2, U2)

    norm = [np.vdot(U2[:, n], U1[:, n]) for n in range(ntrans)]

    signal = np.zeros(len(omegas), dtype=complex)

    tmp = [np.vdot(dip, U1[:,n]) * np.vdot(U2[:,n], dip)/norm[n] \
           for n in range(ntrans)]

    for j in range(len(omegas)):
        omega = omegas[j]
        signal[j] += sum(tmp / (omega - eigvals1))

    return -2. * signal.imag, eigvals1, dag(U1).dot(dip)
Пример #7
0
def coherent(N, alpha):
    """Generates a coherent state with eigenvalue alpha.

    Constructed using displacement operator on vacuum state.

    Modified from Qutip.

    Parameters
    ----------
    N : int
        Number of Fock states in Hilbert space.

    alpha : float/complex
        Eigenvalue of coherent state.

    offset : int (default 0)
        The lowest number state that is included in the finite number state
        representation of the state. Using a non-zero offset will make the
        default method 'analytic'.

    method : string {'operator', 'analytic'}
        Method for generating coherent state.

    Returns
    -------
    state : qobj
        Qobj quantum object for coherent state

    Examples
    --------
    >>> coherent(5,0.25j)
    Quantum object: dims = [[5], [1]], shape = [5, 1], type = ket
    Qobj data =
    [[  9.69233235e-01+0.j        ]
     [  0.00000000e+00+0.24230831j]
     [ -4.28344935e-02+0.j        ]
     [  0.00000000e+00-0.00618204j]
     [  7.80904967e-04+0.j        ]]

    Notes
    -----
    Select method 'operator' (default) or 'analytic'. With the
    'operator' method, the coherent state is generated by displacing
    the vacuum state using the displacement operator defined in the
    truncated Hilbert space of size 'N'. This method guarantees that the
    resulting state is normalized. With 'analytic' method the coherent state
    is generated using the analytical formula for the coherent state
    coefficients in the Fock basis. This method does not guarantee that the
    state is normalized if truncated to a small number of Fock states,
    but would in that case give more accurate coefficients.

    """

    x = basis(N, 0)
    a = destroy(N)
    D = la.expm(alpha * dag(a) - np.conj(alpha) * a)

    return D @ x
Пример #8
0
def func(rho, h0, c_ops, l_ops):
    """
    right-hand side of the master equation
    """
    rhs = -1j * commutator(h0, rho)

    for i in range(len(c_ops)):
        c_op = c_ops[i]
        l_op = l_ops[i]
        rhs -= commutator(c_op, l_op.dot(rho) - rho.dot(dag(l_op)))
    return rhs
Пример #9
0
def linear_absorption(omegas, ham, dip, rho0, c_ops=[], ntrans=1):
    """
    Note that the eigenvectors of the liouvillian L and L^\dag have to
    be ordered in parallel!

    Parameters
    ----------
    omegas : TYPE
        DESCRIPTION.
    ham : TYPE
        DESCRIPTION.
    dip : TYPE
        DESCRIPTION.
    rho0 : 2d array
        initial density matrix
    c_ops : TYPE, optional
        DESCRIPTION. The default is [].
    ntrans : int, optional
        Number of transitions to be computed. The default is 1.

    Returns
    -------
    signal : TYPE
        DESCRIPTION.

    """

    # dissipation
    dissipator = 0.
    for c_op in c_ops:
        dissipator += lindblad_dissipator(c_op)

    liouvillian = operator_to_superoperator(ham) + 1j * dissipator

    eigvals1, U1 = eigs(liouvillian, k=ntrans, which='LR')
    eigvals1, U1 = sort(eigvals1, U1)

    eigvals2, U2 = eigs(dag(liouvillian), k=ntrans, which='LR')
    eigvals2, U2 = sort(eigvals2, U2)

    norm = [np.vdot(U2[:, n], U1[:, n]) for n in range(ntrans)]

    signal = np.zeros(len(omegas), dtype=complex)

    tmp = [np.vdot(dip.flatten(), U1[:,n]) * np.vdot(U2[:,n], \
          dip.dot(rho0).flatten()) / norm[n] for n in range(ntrans)]

    for j in range(len(omegas)):
        omega = omegas[j]
        signal[j] += sum(tmp / (omega - eigvals1))

    return -2. * signal.imag
Пример #10
0
def redfield_tensor(H, a_ops, spectra, secular=False):

    for a in a_ops:
        if issparse(a):
            if not isherm(a.todense()):
                raise TypeError("Operators in a_ops must be Hermitian.")
        elif not isherm(a):
            raise TypeError("Operators in a_ops must be Hermitian.")

    if issparse(H):
        evals, evecs = eigh(H.todense())
    else:
        evals, evecs = eigh(H)

    print('eigenvalues', evals)

    # pre-calculate matrix elements and spectral densities
    # W[m,n] = real(evals[m] - evals[n])
    W = np.real(evals[:, np.newaxis] - evals[np.newaxis, :])

    # bath spectral density at transition energies

    K = len(a_ops)
    N = len(evals)

    C = []
    for k in range(K):

        c = np.zeros((N, N))
        for n in range(N):
            for m in range(N):
                c[n, m] = spectra[k](-W[n, m])

        C.append(c)

        # C = [s(-W) for s in spectra]

    # transfrom a_ops to eigenbasis
    A = [transform(a, evecs) for a in a_ops]

    # calc the lambda operators
    L = [C[k] * A[k] for k in range(K)]

    R = 0
    # superoperator
    for k in range(K):
        a = A[k]
        l = L[k]
        R += op2sop(a).dot(left(l) - right(dag(l)))

    return csr_matrix(-1j * op2sop(np.diag(evals)) - R), evecs
Пример #11
0
def absorption_eseries(omegas, L, edip, rho0, ntrans=1):
    """
    Compute absorption spectrum by diagonalizing the liouvillian L.
    Note that the eigenvectors of the L and L^\dag have to
    be ordered in parallel!

    Parameters
    ----------
    omegas : TYPE
        frequencies for the signal
    L : ndarray
        liouvillian superoperator
    edip : TYPE
        electric dipole.
    rho0 : 2d array
        initial density matrix
    c_ops : TYPE, optional
        DESCRIPTION. The default is [].
    ntrans : int, optional
        Number of transitions to be computed. The default is 1.

    Returns
    -------
    signal : TYPE
        DESCRIPTION.

    """

    eigvals1, U1 = eigs(L, k=ntrans, which='LR')
    eigvals1, U1 = sort(eigvals1, U1)

    eigvals2, U2 = eigs(dag(L), k=ntrans, which='LR')
    eigvals2, U2 = sort(eigvals2, U2)

    norm = [np.vdot(U2[:, n], U1[:, n]) for n in range(ntrans)]

    signal = np.zeros(len(omegas), dtype=complex)

    tmp = [np.vdot(edip.flatten(), U1[:,n]) * np.vdot(U2[:,n], \
          edip.dot(rho0).flatten()) / norm[n] for n in range(ntrans)]

    for j in range(len(omegas)):
        omega = omegas[j]
        signal[j] += sum(tmp / (omega - eigvals1))

    return -2. * signal.imag
Пример #12
0
def cdot(a, b):
    """
    matrix product of a.H.dot(b)

    Parameters
    ----------
    a : TYPE
        DESCRIPTION.
    b : TYPE
        DESCRIPTION.

    Returns
    -------
    None.

    """
    return dag(a) @ b
Пример #13
0
def kraus(a):
    """
    Kraus superoperator a rho a^\dag = a^\dag_R a_L

    Parameters
    ----------
    a : TYPE
        DESCRIPTION.

    Returns
    -------
    TYPE
        DESCRIPTION.

    """
    al = left(a)
    ar = right(dag(a))

    return ar.dot(al)
Пример #14
0
    def correlation_3p_2t(self, psi0, oplist, dt, Nt, Ntau):
        """
        <A(t)B(t+tau)C(t)>
        Parameters
        ----------
        oplist: list of arrays
            [a, b, c]
        psi0: array
            initial state
        dt
        nt: integer
            number of time steps for t
        ntau: integer
            time steps for tau

        Returns
        -------

        """
        H = self.H
        psi_t = _quantum_dynamics(H, psi0, dt=dt, Nt=Nt).psilist

        a_op, b_op, c_op = oplist

        corr_mat = np.zeros([Nt, Ntau], dtype=complex)

        for t_idx, psi in enumerate(psi_t):
            psi_tau_ket = _quantum_dynamics(H, c_op @ psi, dt=dt,
                                            Nt=Ntau).psilist
            psi_tau_bra = _quantum_dynamics(H, dag(a_op) @ psi, dt=dt,
                                            Nt=Ntau).psilist

            corr_mat[t_idx, :] = [
                np.vdot(psi_tau_bra[j], b_op @ psi_tau_ket[j])
                for j in range(Ntau)
            ]

        return corr_mat
Пример #15
0
def polarizability(w, Er, Ev, d, use_rwa=True):
    """
    Compute the vibrational/electronic polarizability using sum-over-states formula

    \alpha_{ji}(w) = d_{jv} d_{vi}/(E_v - E_i - w)

    Parameters
    ----------
    w : TYPE
        DESCRIPTION.
    Er : TYPE
        eigenenergies of resonant states.
    Ev : TYPE
        eigenenergies of virtual states.
    d : TYPE
        DESCRIPTION.
    use_rwa : TYPE, optional
        DESCRIPTION. The default is True.

    Returns
    -------
    a : TYPE
        DESCRIPTION.

    """
    ne = len(Er)
    nv = len(Ev)

    assert d.shape == (nv, ne)

    # denominator
    dE = Ev[:, np.newaxis] - Er - w

    a = dag(d).dot(d / dE)

    return a
Пример #16
0
def schmidt_decompose(f, dp, dq, nmodes=5, method='rdm'):
    """
    kernel method
    f: 2D array,
        input function to be decomposed
    nmodes: int
        number of modes to be kept
    method: str
        rdm or svd
    """
    if method == 'rdm':
        kernel1 = f.dot(dag(f)) * dq * dp
        kernel2 = f.T.dot(f.conj()) * dp * dq

        print('c: Schmidt coefficients')
        s, phi = np.linalg.eig(kernel1)
        s1, psi = np.linalg.eig(kernel2)

        phi /= np.sqrt(dp)
        psi /= np.sqrt(dq)
    elif method == 'svd':
        raise NotImplementedError

    return np.sqrt(s[:nmodes]), phi[:, :nmodes], psi[:, :nmodes]
Пример #17
0
    dm.setdiag(w)
    return dm.tocsr()


N = 10
cav = Cavity(1.0, N)

H = cav.hamiltonian
H = csr_matrix(H)

kappa = 0.25

n_th = 2.0  # bath temperature in terms of excitation number
a = cav.get_annihilate()
c_ops = [np.sqrt(kappa * (1 + n_th)) * a, np.sqrt(kappa * n_th) * dag(a)]

num_op = cav.get_num()

rho0 = thermal_dm(N, 2)

print(rho0)

tlist = np.linspace(0, 10, 200)

corr(H, rho0, [dag(a), num_op, a], c_ops, tlist, lindblad)

t, corr = np.genfromtxt('cor.dat', unpack=True, dtype=complex)

import matplotlib.pyplot as plt
Пример #18
0
def absorption(mol, omegas, c_ops):
    """
    superoperator formalism for absorption spectrum

    Parameters
    ----------
    mol : TYPE
        DESCRIPTION.
    omegas: vector
        detection window of the spectrum
    c_ops : TYPE
        list of collapse operators

    Returns
    -------
    None.

    """

    gamma = 0.02

    l = op2sop(H) + 1j * c_op.to_linblad(gamma=gamma)

    ntrans = 3 * nstates  # number of transitions
    eigvals1, U1 = eigs(l, k=ntrans, which='LR')

    eigvals1, U1 = sort(eigvals1, U1)

    # print(eigvals1)

    omegas = np.linspace(0.1, 10.5, 200)

    rho0 = Qobj(dims=[10, 10])
    rho0.data[0, 0] = 1.0

    ops = [sz, sz]

    # out = correlation_2p_1t(omegas, rho0, ops, L)
    # print(eigvecs)
    eigvals2, U2 = eigs(dag(l), k=ntrans, which='LR')

    eigvals2, U2 = sort(eigvals2, U2)

    #idx = np.where(eigvals2.real > 0.2)[0]
    #print(idx)

    norm = [np.vdot(U2[:, n], U1[:, n]) for n in range(ntrans)]

    la = np.zeros(len(omegas), dtype=complex)  # linear absorption
    for j, omega in enumerate(omegas):

        for n in range(ntrans):

            la[j] += np.vdot(dip.to_vector(), U1[:,n]) * \
                 np.vdot(U2[:,n], dip.dot(rho0).to_vector()) \
                 /(omega - eigvals1[n]) / norm[n]

    fig, ax = plt.subplots()
    # ax.scatter(eigvals1.real, eigvals1.imag)
    ax.plot(omegas, -2 * la.imag)

    return
Пример #19
0
def lindblad_dissipator(l, gamma=1.):
    return gamma * (kron(l, l.conj()) - operator_to_superoperator(
        dag(l).dot(l), type='anticommutator'))
Пример #20
0
def obs(rho, a):
    return np.vdot(operator_to_vector(dag(a)), rho)
Пример #21
0
def _redfield(R,
              rho0,
              evecs=None,
              Nt=1,
              dt=0.005,
              t0=0,
              e_ops=[],
              return_result=True):
    """
    time propagation of the Redfield quantum master equation with RK4

    Input
    -------
    R: 2d array
        Redfield tensor

    rho0: 2d array
        initial density matrix

    Nt: total number of time steps

    dt: time step
    e_ops: list of observable operators

    Returns
    =========
    rho: 2D array
        density matrix at time t = Nt * dt
    """

    N = rho0.shape[0]
    # initialize the density matrix
    if e_ops is None:
        e_ops = []

    # basis transformation
    if evecs is not None:
        rho0 = transform(rho0, evecs)
        e_ops = [transform(e, evecs) for e in e_ops]

    rho = rho0.copy()
    rho = dm2vec(rho).astype(complex)

    # tf = t0 + dt * Nt
    # result = solve_ivp(rhs, t_span=(t0, tf), y0=rho0, vectorized=True, args=(R, ))

    t = t0

    if return_result == False:

        f_obs = open('obs.dat', 'w')
        fmt = '{} ' * (len(e_ops) + 1) + '\n'

        for k in range(Nt):

            # compute observables
            # observables = np.zeros(len(e_ops), dtype=complex)
            # for i, obs_op in enumerate(e_ops):

            observables = [obs_dm(rho, e) for e in e_ops]

            t += dt
            rho = rk4(rho, rhs, dt, R)

            # dipole-dipole auto-corrlation function
            #cor = np.trace(np.matmul(d, rho))

            # take a partial trace to obtain the rho_el

            f_obs.write(fmt.format(t, *observables))

        f_obs.close()
        # f_dm.close()

        return rho

    else:

        rholist = []  # store density matries

        result = Result(dt=dt, Nt=Nt, rho0=rho0)

        observables = np.zeros((Nt, len(e_ops)), dtype=complex)

        for k in range(Nt):

            t += dt
            rho = rk4(rho, rhs, dt, R)

            tmp = np.reshape(rho, (N, N))
            rholist.append(transform(tmp, dag(evecs)))

            observables[k, :] = [obs_dm(tmp, e) for e in e_ops]

        result.observables = observables
        result.rholist = rholist

        return result
Пример #22
0
 def to_linblad(self, gamma=1.):
     l = self.data
     return gamma * (kron(l, l.conj()) - \
             operator_to_superoperator(dag(l).dot(l), type='anticommutator'))
Пример #23
0
def lindblad_dissipator(l):
    return kron(l, l.conj()) - 0.5 *\
                      operator_to_superoperator(dag(l).dot(l), kind='anticommutator')
Пример #24
0
    eigvals1, U1 = eigs(l, k=ntrans, which='LR')

    eigvals1, U1 = sort(eigvals1, U1)

    print(eigvals1.real)

    omegas = np.linspace(0.1, 10.5, 200)

    rho0 = Qobj(dims=[10, 10])
    rho0.data[0, 0] = 1.0

    ops = [sz, sz]

    # out = correlation_2p_1t(omegas, rho0, ops, L)
    # print(eigvecs)
    eigvals2, U2 = eigs(dag(l), k=ntrans, which='LR')

    eigvals2, U2 = sort(eigvals2, U2)

    #idx = np.where(eigvals2.real > 0.2)[0]
    #print(idx)

    norm = [np.vdot(U2[:, n], U1[:, n]) for n in range(ntrans)]

    la = np.zeros(len(omegas), dtype=complex)  # linear absorption
    for j, omega in enumerate(omegas):

        for n in range(ntrans):

            la[j] += np.vdot(dip.to_vector(), U1[:,n]) * \
                 np.vdot(U2[:,n], dip.dot(rho0).to_vector()) \