def L_nonsecular_old(H_vib, A, eps, Gamma, T, J, time_units='cm', silent=False): #Construct non-secular liouvillian ti = time.time() d = H_vib.shape[0] evals, evecs = H_vib.eigenstates() X1, X2, X3, X4 = 0, 0, 0, 0 for i in range(int(d)): for j in range(int(d)): eps_ij = abs(evals[i]-evals[j]) A_ij = A.matrix_element(evecs[i].dag(), evecs[j]) A_ji = (A.dag()).matrix_element(evecs[j].dag(), evecs[i]) Occ = Occupation(eps_ij, T, time_units) IJ = evecs[i]*evecs[j].dag() JI = evecs[j]*evecs[i].dag() # 0.5*np.pi*alpha*(N+1) if abs(A_ij)>0 or abs(A_ji)>0: r_up = 2*np.pi*J(eps_ij, Gamma, eps)*Occ r_down = 2*np.pi*J(eps_ij, Gamma, eps)*(Occ+1) X3+= r_down*A_ij*IJ X4+= r_up*A_ij*IJ X1+= r_up*A_ji*JI X2+= r_down*A_ji*JI L = spre(A*X1) -sprepost(X1,A)+spost(X2*A)-sprepost(A,X2) L+= spre(A.dag()*X3)-sprepost(X3, A.dag())+spost(X4*A.dag())-sprepost(A.dag(), X4) if not silent: print(("It took ", time.time()-ti, " seconds to build the Non-secular RWA Liouvillian")) return -0.5*L
def L_left_lindblad(H, PARAMS): I = qeye(PARAMS['N']) d_h = tensor(PARAMS['A_L'], I) J_leads = J_Lorentzian Lambda_up = lambda x : Lamdba_complex_rate(x, J_leads, PARAMS['mu_L'], PARAMS['T_L'], PARAMS['Gamma_L'], PARAMS['delta_L'], PARAMS['Omega_L'], type='p', real_only=True) Lambda_down = lambda x : Lamdba_complex_rate(x, J_leads, PARAMS['mu_L'], PARAMS['T_L'], PARAMS['Gamma_L'], PARAMS['delta_L'], PARAMS['Omega_L'], type='m', real_only=True) energies, states = H.eigenstates() L=0 for i in range(len(energies)): for j in range(len(energies)): eta_ij = energies[i] - energies[j] if (abs(eta_ij)>0):# take limit of rates going to zero d_h_ij = d_h.matrix_element(states[i].dag(), states[j]) d_h_ij_sq = d_h_ij*d_h_ij.conjugate() # real by construction if (abs(d_h_ij_sq)>0): # No need to do anything if the matrix element is zero IJ = states[i]*states[j].dag() JI = states[j]*states[i].dag() JJ = states[j]*states[j].dag() II = states[i]*states[i].dag() rate_up = Lambda_up(-eta_ij) # evaluated at positive freq diffs rate_down = Lambda_down(-eta_ij) print(rate_down) T1 = rate_up*spre(II)+rate_down*spre(JJ) T2 = rate_up.conjugate()*spost(II)+rate_down.conjugate()*spost(JJ) T3 = (rate_up*sprepost(JI, IJ)+rate_down*sprepost(IJ,JI)) L += d_h_ij_sq*(0.5*(T1 + T2) - T3) return -L
def L_full_secular(H_vib, A, eps, Gamma, T, J, time_units='cm', silent=False): ''' Initially assuming that the vibronic eigenstructure has no degeneracy and the secular approximation has been made ''' ti = time.time() d = H_vib.shape[0] L = 0 eVals, eVecs = H_vib.eigenstates() A_dag = A.dag() terms = 0 for l in range(int(d)): for m in range(int(d)): for p in range(int(d)): for q in range(int(d)): secular_freq = (eVals[l] - eVals[m]) - (eVals[p] - eVals[q]) if abs(secular_freq) < 1E-10: terms += 1 A_lm = A.matrix_element(eVecs[l].dag(), eVecs[m]) A_lm_star = A_dag.matrix_element( eVecs[m].dag(), eVecs[l]) A_pq = A.matrix_element(eVecs[p].dag(), eVecs[q]) A_pq_star = A_dag.matrix_element( eVecs[q].dag(), eVecs[p]) coeff_1 = A_lm * A_pq_star coeff_2 = A_lm_star * A_pq eps_pq = abs(eVals[p] - eVals[q]) Occ = Occupation(eps_pq, T, time_units) r_up = np.pi * J(eps_pq, Gamma, eps) * Occ r_down = np.pi * J(eps_pq, Gamma, eps) * (Occ + 1) LM = eVecs[l] * eVecs[m].dag() ML = LM.dag() PQ = eVecs[p] * eVecs[q].dag() QP = PQ.dag() """ if abs(secular_freq) !=0: print (abs(secular_freq), r_up, A_lm, A_lm_star, A_pq, A_pq_star, r_down, l,m,p,q, m==q, l==p) """ if abs(r_up * coeff_1) > 0: L += r_up * coeff_1 * (spre(LM * QP) - sprepost(QP, LM)) if abs(r_up * coeff_2) > 0: L += r_up * coeff_2 * (spost(PQ * ML) - sprepost(ML, PQ)) if abs(r_down * coeff_1) > 0: L += r_down * coeff_1 * (spre(ML * PQ) - sprepost(PQ, ML)) if abs(r_down * coeff_2) > 0: L += r_down * coeff_2 * (spost(QP * LM) - sprepost(LM, QP)) if not silent: print(("It took ", time.time() - ti, " seconds to build the secular Liouvillian")) print(( "Secular approximation kept {:0.2f}% of total ME terms. \n".format( 100 * float(terms) / (d * d * d * d)))) return -L
def L_EM_lindblad(splitting, col_em, Gamma, T, J, time_units='cm', silent=False): # col_em is collapse operator ti = time.time() L = 0 EMnb = Occupation(splitting, T, time_units) L+= 2*np.pi*J(splitting, Gamma, splitting)*(EMnb+1)*(sprepost(col_em, col_em.dag())-0.5*(spre(col_em.dag()*col_em) +spost(col_em.dag()*col_em))) L+= 2*np.pi*J(splitting, Gamma, splitting)*EMnb*(sprepost(col_em.dag(), col_em)-0.5*(spre(col_em*col_em.dag())+ spost(col_em*col_em.dag()))) if not silent: print(("It took ", time.time()-ti, " seconds to build the electronic-Lindblad Liouvillian")) return L
def liouvillian_build(H_0, A, gamma, wRC, T_C): # Now this function has to construct the liouvillian so that it can be passed to mesolve H_0, A, Chi, Xi = RCME_operators(H_0, A, gamma, beta_f(T_C)) L = 0 L -= spre(A * Chi) L += sprepost(A, Chi) L += sprepost(Chi, A) L -= spost(Chi * A) L += spre(A * Xi) L += sprepost(A, Xi) L -= sprepost(Xi, A) L -= spost(Xi * A) return L, Chi + Xi
def channel(self, loss, dephasing, verbose=False): data_kraus = loss.kraus ancilla_phase = loss.propagate(self.ancilla.dim, self.code.N, self.ancilla.N) nkraus = len(data_kraus) ndata_meas = len(self.data_meas.povm_elements) nancilla_meas = len(self.ancilla_meas.povm_elements) cmat1 = np.zeros((ndata_meas, nkraus, 2, 2), dtype=complex) cmat2 = np.zeros((nancilla_meas, nkraus, 2, 2), dtype=complex) # compute c1(x1|k;a;b), c2(x2|k;a;b) matrices for k, (n, p) in enumerate(zip(data_kraus, ancilla_phase)): cmat1[:, k, :, :] = np.reshape( [qt.expect(m, n*dephasing(keta*ketb.dag())*n.dag()) for m in self.data_meas.povm_elements for keta in [self.code.plus, self.code.minus] for ketb in [self.code.plus, self.code.minus]], cmat1[:, k, :, :].shape) cmat2[:, k, :, :] = np.reshape( [qt.expect(m, p*keta*ketb.dag()*p.dag()) for m in self.ancilla_meas.povm_elements for keta in [self.ancilla.plus, self.ancilla.minus] for ketb in [self.ancilla.plus, self.ancilla.minus]], cmat2[:, k, :, :].shape) # compute p1(x1|k;a), p2(x2|k;a) matrices pmat1 = np.diagonal(cmat1, axis1=2, axis2=3) pmat2 = np.diagonal(cmat2, axis1=2, axis2=3) # compute c(x1, x2| a, a', b') and p(x1, x2| a, b) cmat = np.moveaxis(np.tensordot(cmat1, cmat2, axes=([1], [1])), 3, 1) pmat = np.moveaxis(np.tensordot(pmat1, pmat2, axes=([1], [1])), 2, 1) # determine most likely a, b abmat = np.empty((ndata_meas, nancilla_meas), dtype=object) for x1 in range(ndata_meas): for x2 in range(nancilla_meas): idx = (x1, x2, Ellipsis) a, b = np.unravel_index(np.argmax(pmat[idx]), pmat[idx].shape) abmat[x1, x2] = (a, b) # construct channel channel = qt.Qobj() Paulis = np.array( [[self.code_out.identity, self.code_out.logical_Z_allspace], [self.code_out.logical_X_allspace, self.code_out.logical_X_allspace * self.code_out.logical_Z_allspace]], dtype=type(self.code_out.identity)) for a1, a2 in np.ndindex(2, 2): for b1, b2 in np.ndindex(2, 2): for x1 in range(ndata_meas): for x2 in range(nancilla_meas): r = Paulis[abmat[x1, x2]].dag() channel += (cmat[x1, x2, a1, b1, a2, b2] * qt.sprepost(r*Paulis[a1, a2], Paulis[b1, b2].dag()*r.dag())) return 0.25*channel
def __init__(self, H_S, L1, L2, S_matrix=None, c_ops_markov=None, options=None): if options is None: self.options = qt.Options() else: self.options = options self.H_S = H_S self.sysdims = H_S.dims if isinstance(L1, qt.Qobj): self.L1 = [L1] else: self.L1 = L1 if isinstance(L2, qt.Qobj): self.L2 = [L2] else: self.L2 = L2 if not len(self.L1) == len(self.L2): raise ValueError('L1 and L2 has to be of equal length.') if isinstance(c_ops_markov, qt.Qobj): self.c_ops_markov = [c_ops_markov] else: self.c_ops_markov = c_ops_markov if S_matrix is None: self.S_matrix = np.identity(len(self.L1)) else: self.S_matrix = S_matrix # create system identity superoperator self.Id = qt.qeye(H_S.shape[0]) self.Id.dims = self.sysdims self.Id = qt.sprepost(self.Id, self.Id) self.store_states = self.options.store_states
def test_sprepost(self): U1 = rand_unitary(3) U2 = rand_unitary(3) S1 = spre(U1) * spost(U2) S2 = sprepost(U1, U2) assert_(S1 == S2)
def pauli_channel_2_qubit(num_of_paulis): paulis_probs = np.random.random_sample(num_of_paulis) paulis_probs = paulis_probs / sum(paulis_probs) channel = qt.Qobj() for i in range(num_of_paulis): pauli_rand = qt.tensor(g_1Q[rd.randint(0, 3)], g_1Q[rd.randint(0, 3)]) channel += paulis_probs[i] * qt.sprepost(pauli_rand, pauli_rand) return channel
def encoder(self, kraus=False): if self._encoder is None: self._encoder = (self.zero * qt.basis(2, 0).dag() + self.one * qt.basis(2, 1).dag()) if kraus: return self._encoder else: return qt.sprepost(self._encoder, self._encoder.dag())
def test_dqd_current(): "Counting statistics: current and current noise in a DQD model" G = 0 L = 1 R = 2 sz = qutip.projection(3, L, L) - qutip.projection(3, R, R) sx = qutip.projection(3, L, R) + qutip.projection(3, R, L) sR = qutip.projection(3, G, R) sL = qutip.projection(3, G, L) w0 = 1 tc = 0.6 * w0 GammaR = 0.0075 * w0 GammaL = 0.0075 * w0 nth = 0.00 eps_vec = np.linspace(-1.5 * w0, 1.5 * w0, 20) J_ops = [GammaR * qutip.sprepost(sR, sR.dag())] c_ops = [ np.sqrt(GammaR * (1 + nth)) * sR, np.sqrt(GammaR * (nth)) * sR.dag(), np.sqrt(GammaL * (nth)) * sL, np.sqrt(GammaL * (1 + nth)) * sL.dag() ] current = np.zeros(len(eps_vec)) noise = np.zeros(len(eps_vec)) for n, eps in enumerate(eps_vec): H = (eps / 2 * sz + tc * sx) L = qutip.liouvillian(H, c_ops) rhoss = qutip.steadystate(L) current[n], noise[n] = qutip.countstat_current_noise(L, [], rhoss=rhoss, J_ops=J_ops) current2 = qutip.countstat_current(L, rhoss=rhoss, J_ops=J_ops) assert abs(current[n] - current2) < 1e-8 current2 = qutip.countstat_current(L, c_ops, J_ops=J_ops) assert abs(current[n] - current2) < 1e-8 current_target = (tc**2 * GammaR / (tc**2 * (2 + GammaR / GammaL) + GammaR**2 / 4 + eps_vec**2)) noise_target = current_target * ( 1 - (8 * GammaL * tc**2 * (4 * eps_vec**2 * (GammaR - GammaL) + GammaR * (3 * GammaL * GammaR + GammaR**2 + 8 * tc**2)) / (4 * tc**2 * (2 * GammaL + GammaR) + GammaL * GammaR**2 + 4 * eps_vec**2 * GammaL)**2)) np.testing.assert_allclose(current, current_target, atol=1e-4) np.testing.assert_allclose(noise, noise_target, atol=1e-4)
def liouvillian_build_new(H_0, A, gamma, wRC, T_C): # Now this function has to construct the liouvillian so that it can be passed to mesolve H_0, A, Chi, Xi = RCME_operators(H_0, A, gamma, beta_f(T_C)) Z = Chi + Xi Z_dag = Z.dag() L = 0 #L+=spre(A*Z_dag) #L-=sprepost(A, Z) #L-=sprepost(Z_dag, A) #L+=spost(Z_dag*A) L -= spre(A * Z_dag) L += sprepost(A, Z) L += sprepost(Z_dag, A) L -= spost(Z * A) print("new L built") return L, Z
def L_vib_lindblad(H_vib, A, eps, Gamma, T, J, time_units='cm', silent=False): ''' Initially assuming that the vibronic eigenstructure has no degeneracy and the secular approximation has been made ''' ti = time.time() d = H_vib.shape[0] ti = time.time() L = 0 eig = H_vib.eigenstates() eVals = eig[0] eVecs = eig[1] # come out like kets l = 0 occs = [] for i in range(int(d)): l = 0 for j in range(int(d)): t_0 = time.time( ) # initial time reference for tracking slow calculations lam_ij = A.matrix_element(eVecs[i].dag(), eVecs[j]) #lam_mn = (A.dag()).matrix_element(eVecs[n].dag(), eVecs[m]) lam_ij_sq = lam_ij * lam_ij.conjugate() # real by construction eps_ij = abs(eVals[i] - eVals[j]) if abs(lam_ij_sq) > 0: IJ = eVecs[i] * eVecs[j].dag() JI = eVecs[j] * eVecs[i].dag() JJ = eVecs[j] * eVecs[j].dag() II = eVecs[i] * eVecs[i].dag() Occ = Occupation(eps_ij, T, time_units) r_up = 2 * np.pi * J(eps_ij, Gamma, eps) * Occ r_down = 2 * np.pi * J(eps_ij, Gamma, eps) * (Occ + 1) T1 = r_up * spre(II) + r_down * spre(JJ) T2 = r_up.conjugate() * spost(II) + r_down.conjugate() * spost( JJ) T3 = (r_up * sprepost(JI, IJ) + r_down * sprepost(IJ, JI)) L += lam_ij_sq * (0.5 * (T1 + T2) - T3) l += 1 if not silent: print(("It took ", time.time() - ti, " seconds to build the vibronic Lindblad Liouvillian")) return -L
def L_wc_analytic(detuning=0., Rabi=0, alpha=0., w0=0., Gamma=0., T=0., tol=1e-7): energies, states = exciton_states(detuning, Rabi) dark_proj = states[0] * states[0].dag() bright_proj = states[1] * states[1].dag() ct_p = states[1] * states[0].dag() ct_m = states[0] * states[1].dag() cross_term = (ct_p + ct_m) epsilon = -detuning V = Rabi / 2 eta = sqrt(epsilon**2 + 4 * V**2) # Bath 1 (only one bath) G = (lambda x: (DecayRate(x, beta_f(T), _J_underdamped, Gamma, w0, imag_part=True, alpha=alpha, tol=tol))) G_0 = G(0.) G_p = G(eta) G_m = G(-eta) site_1 = (0.5 / eta) * ((eta + epsilon) * bright_proj + (eta - epsilon) * dark_proj + 2 * V * cross_term) Z_1 = (0.5 / eta) * (G_0 * ((eta + epsilon) * bright_proj + (eta - epsilon) * dark_proj) + 2 * V * (ct_p * G_p + ct_m * G_m)) L = -qt.spre(site_1 * Z_1) + qt.sprepost(Z_1, site_1) L += -qt.spost(Z_1.dag() * site_1) + qt.sprepost(site_1, Z_1.dag()) return L
def test_dqd_current(): "Counting statistics: current and current noise in a DQD model" G = 0 L = 1 R = 2 sz = projection(3, L, L) - projection(3, R, R) sx = projection(3, L, R) + projection(3, R, L) sR = projection(3, G, R) sL = projection(3, G, L) w0 = 1 tc = 0.6 * w0 GammaR = 0.0075 * w0 GammaL = 0.0075 * w0 nth = 0.00 eps_vec = np.linspace(-1.5*w0, 1.5*w0, 20) J_ops = [GammaR * sprepost(sR, sR.dag())] c_ops = [np.sqrt(GammaR * (1 + nth)) * sR, np.sqrt(GammaR * (nth)) * sR.dag(), np.sqrt(GammaL * (nth)) * sL, np.sqrt(GammaL * (1 + nth)) * sL.dag(), ] I = np.zeros(len(eps_vec)) S = np.zeros(len(eps_vec)) for n, eps in enumerate(eps_vec): H = (eps/2 * sz + tc * sx) L = liouvillian(H, c_ops) rhoss = steadystate(L) I[n], S[n] = countstat_current_noise(L, [], rhoss=rhoss, J_ops=J_ops) I2 = countstat_current(L, rhoss=rhoss, J_ops=J_ops) assert_(abs(I[n] - I2) < 1e-8) I2 = countstat_current(L, c_ops, J_ops=J_ops) assert_(abs(I[n] - I2) < 1e-8) Iref = tc**2 * GammaR / (tc**2 * (2 + GammaR/GammaL) + GammaR**2/4 + eps_vec**2) Sref = 1 * Iref * ( 1 - 8 * GammaL * tc**2 * (4 * eps_vec**2 * (GammaR - GammaL) + GammaR * (3 * GammaL * GammaR + GammaR**2 + 8*tc**2)) / (4 * tc**2 * (2 * GammaL + GammaR) + GammaL * GammaR**2 + 4 * eps_vec**2 * GammaL)**2 ) assert_allclose(I, Iref, 1e-4) assert_allclose(S, Sref, 1e-4)
def L_non_rwa(H_vib, A, w_0, Gamma, T_EM, J, principal=False, silent=False, alpha=0., tol=1e-5): ti = time.time() beta = beta_f(T_EM) eVals, eVecs = H_vib.eigenstates() #J=J_minimal # J_minimal(omega, Gamma, omega_0) d_dim = len(eVals) G = 0 for i in range(d_dim): for j in range(d_dim): eta = eVals[i] - eVals[j] s = eVecs[i] * (eVecs[j].dag()) #print A.matrix_element(eVecs[i].dag(), eVecs[j]) overlap = A.matrix_element(eVecs[i].dag(), eVecs[j]) s *= A.matrix_element(eVecs[i].dag(), eVecs[j]) s *= DecayRate(eta, beta, J, Gamma, w_0, imag_part=principal, alpha=alpha, tol=tol) G += s G_dag = G.dag() # Initialise liouvilliian L = qt.spre(A * G) - qt.sprepost(G, A) L += qt.spost(G_dag * A) - qt.sprepost(A, G_dag) if not silent: print(("Calculating non-RWA Liouvilliian took {} seconds.".format( time.time() - ti))) return -L
def test_ttmsolve_jc_model(): """ Checks the output of ttmsolve using an example from Jaynes-Cumming model, which can also be found in the qutip-notebooks repository. """ # Define Hamiltonian and states N, kappa, g = 3, 1.0, 10 a = qt.tensor(qt.qeye(2), qt.destroy(N)) sm = qt.tensor(qt.sigmam(), qt.qeye(N)) sz = qt.tensor(qt.sigmaz(), qt.qeye(N)) H = g * (a.dag() * sm + a * sm.dag()) c_ops = [np.sqrt(kappa) * a] # identity superoperator Id = qt.tensor(qt.qeye(2), qt.qeye(N)) E0 = qt.sprepost(Id, Id) # partial trace superoperator ptracesuper = qt.tensor_contract(E0, (1, N)) # initial states rho0a = qt.ket2dm(qt.basis(2, 0)) psi0c = qt.basis(N, 0) rho0c = qt.ket2dm(psi0c) rho0 = qt.tensor(rho0a, rho0c) superrho0cav = qt.sprepost(qt.tensor(qt.qeye(2), psi0c), qt.tensor(qt.qeye(2), psi0c.dag())) # calculate exact solution using mesolve times = np.arange(0, 5.0, 0.1) exactsol = qt.mesolve(H, rho0, times, c_ops, []) exact_z = qt.expect(sz, exactsol.states) # solve using transfer method learning_times = np.arange(0, 2.0, 0.1) Et_list = qt.mesolve(H, E0, learning_times, c_ops, []).states learning_maps = [ptracesuper * (Et * superrho0cav) for Et in Et_list] ttmsol = ttmsolve(learning_maps, rho0a, times) ttm_z = qt.expect(qt.sigmaz(), ttmsol.states) # check that ttm result and exact solution are close in the learning times assert np.allclose(ttm_z, exact_z, atol=1e-5)
def liouvillian(epsilon, delta, J, T): L = 0 # Initialise liouvilliian Z = 0 # initialise operator Z #beta = 1 /(T* 0.695) beta = 7.683/T eta = np.sqrt(epsilon**2 + delta**2) # Here I define the eigenstates of the H_s H = qt.Qobj([[-epsilon/2., delta/2],[delta/2, epsilon/2.]]) eVecs = H.eigenstates()[1] psi_p = (1/np.sqrt(2*eta))*(np.sqrt(eta-epsilon)*qt.basis(2,0) + np.sqrt(eta+epsilon)*qt.basis(2,1)) psi_m = (-1/np.sqrt(2*eta))*(np.sqrt(eta+epsilon)*qt.basis(2,0) - np.sqrt(eta-epsilon)*qt.basis(2,1)) #print H.eigenstates() # Jake's eigenvectors #psi_p = (1/np.sqrt(2*eta))*(np.sqrt(eta+epsilon)*qt.basis(2,0) - np.sqrt(eta-epsilon)*qt.basis(2,1)) #psi_m = (1/np.sqrt(2*eta))*(np.sqrt(eta-epsilon)*qt.basis(2,0) + np.sqrt(eta+epsilon)*qt.basis(2,1)) sigma_z = (1/eta)*(epsilon*(psi_p*psi_p.dag()-psi_m*psi_m.dag()) + delta*(psi_p*psi_m.dag() + psi_m*psi_p.dag())) Z = (1/eta)*(epsilon*(psi_p*psi_p.dag()-psi_m*psi_m.dag() )*Gamma(0, beta, J) + delta*(Gamma(eta, beta, J)*psi_p*psi_m.dag() + Gamma(-eta,beta, J)*psi_m*psi_p.dag())) L += qt.spre(sigma_z*Z) - qt.sprepost(Z, sigma_z) L += qt.spost(Z.dag()*sigma_z) - qt.sprepost(sigma_z, Z.dag()) return -L
def test_sprepost_td(self): "Superoperator: sprepost, time-dependent" # left QobjEvo assert_(sprepost(self.t1, self.q2)(.5) == sprepost(self.t1(.5), self.q2)) # left QobjEvo assert_(sprepost(self.q2, self.t1)(.5) == sprepost(self.q2, self.t1(.5))) # left 2 QobjEvo, one cte assert_(sprepost(self.t1, self.t2)(.5) == sprepost(self.t1(.5), self.t2(.5)))
def testMETDDecayAsArray(self): "mesolve: time-dependence as array with super as init cond" me_error = 1e-5 N = 10 a = destroy(N) H = a.dag() * a psi0 = basis(N, 9) rho0vec = operator_to_vector(psi0 * psi0.dag()) E0 = sprepost(qeye(N), qeye(N)) kappa = 0.2 tlist = np.linspace(0, 10, 1000) c_op_list = [[a, np.sqrt(kappa * np.exp(-tlist))]] out1 = mesolve(H, psi0, tlist, c_op_list, []) out2 = mesolve(H, E0, tlist, c_op_list, []) fid = self.fidelitycheck(out1, out2, rho0vec) assert_(max(abs(1.0 - fid)) < me_error, True)
def testMETDDecayAsPartFuncList(self): "mesolve: time-dep. as partial function list with super as init cond" me_error = 1e-5 N = 10 a = destroy(N) H = num(N) psi0 = basis(N, 9) rho0vec = operator_to_vector(psi0 * psi0.dag()) E0 = sprepost(qeye(N), qeye(N)) tlist = np.linspace(0, 10, 100) c_ops = [[[a, partial(lambda t, args, k: np.sqrt(k * np.exp(-t)), k=kappa)]] for kappa in [0.05, 0.1, 0.2]] for idx, kappa in enumerate([0.05, 0.1, 0.2]): out1 = mesolve(H, psi0, tlist, c_ops[idx], []) out2 = mesolve(H, E0, tlist, c_ops[idx], []) fid = self.fidelitycheck(out1, out2, rho0vec) assert_(max(abs(1.0 - fid)) < me_error, True)
def testMETDDecayAsStrList(self): "mesolve: time-dependence as string list with super as init cond" me_error = 1e-6 N = 10 # number of basis states to consider a = destroy(N) H = a.dag() * a psi0 = basis(N, 9) # initial state rho0vec = operator_to_vector(psi0 * psi0.dag()) E0 = sprepost(qeye(N), qeye(N)) kappa = 0.2 # coupling to oscillator c_op_list = [[a, 'sqrt(k*exp(-t))']] args = {'k': kappa} tlist = np.linspace(0, 10, 100) out1 = mesolve(H, psi0, tlist, c_op_list, [], args=args) out2 = mesolve(H, E0, tlist, c_op_list, [], args=args) fid = self.fidelitycheck(out1, out2, rho0vec) assert_(max(abs(1.0 - fid)) < me_error, True)
def testMETDDecayAsStrList(self): "mesolve: time-dependence as string list with super as init cond" me_error = 1e-6 N = 10 # number of basis states to consider a = destroy(N) H = a.dag() * a psi0 = basis(N, 9) # initial state rho0vec = operator_to_vector(psi0 * psi0.dag()) E0 = sprepost(qeye(N), qeye(N)) kappa = 0.2 # coupling to oscillator c_op_list = [[a, "sqrt(k*exp(-t))"]] args = {"k": kappa} tlist = np.linspace(0, 10, 100) out1 = mesolve(H, psi0, tlist, c_op_list, [], args=args) out2 = mesolve(H, E0, tlist, c_op_list, [], args=args) fid = self.fidelitycheck(out1, out2, rho0vec) assert_(max(abs(1.0 - fid)) < me_error, True)
def __init__(self, H_S, L1, L2, S_matrix=None, c_ops_markov=None, integrator='propagator', parallel=False, options=None): if options is None: self.options = qt.Options() else: self.options = options self.H_S = H_S self.sysdims = H_S.dims if isinstance(L1, qt.Qobj): self.L1 = [L1] else: self.L1 = L1 if isinstance(L2, qt.Qobj): self.L2 = [L2] else: self.L2 = L2 if not len(self.L1) == len(self.L2): raise ValueError('L1 and L2 has to be of equal length.') if isinstance(c_ops_markov, qt.Qobj): self.c_ops_markov = [c_ops_markov] else: self.c_ops_markov = c_ops_markov if S_matrix is None: self.S_matrix = np.identity(len(self.L1)) else: self.S_matrix = S_matrix # create system identity superoperator self.Id = qt.qeye(H_S.shape[0]) self.Id.dims = self.sysdims self.Id = qt.sprepost(self.Id, self.Id) self.store_states = self.options.store_states self.integrator = integrator self.parallel = parallel
def testMETDDecayAsPartFuncList(self): "mesolve: time-dep. as partial function list with super as init cond" me_error = 1e-5 N = 10 a = destroy(N) H = num(N) psi0 = basis(N, 9) rho0vec = operator_to_vector(psi0 * psi0.dag()) E0 = sprepost(qeye(N), qeye(N)) tlist = np.linspace(0, 10, 100) c_ops = [[[ a, partial(lambda t, args, k: np.sqrt(k * np.exp(-t)), k=kappa) ]] for kappa in [0.05, 0.1, 0.2]] for idx, kappa in enumerate([0.05, 0.1, 0.2]): out1 = mesolve(H, psi0, tlist, c_ops[idx], []) out2 = mesolve(H, E0, tlist, c_ops[idx], []) fid = self.fidelitycheck(out1, out2, rho0vec) assert_(max(abs(1.0 - fid)) < me_error, True)
def _generator(k, H, L1, L2, S=None, c_ops_markov=None): """ Create a Liouvillian for a cascaded chain of k system copies """ id = qt.qeye(H.dims[0][0]) Id = qt.sprepost(id, id) if S is None: S = np.identity(len(L1)) # create Lindbladian L = qt.Qobj() E0 = Id # first system L += qt.liouvillian(None, [_localop(c, 1, k) for c in L2]) for l in range(1, k): # Identiy superoperator E0 = qt.composite(E0, Id) # Bare Hamiltonian Hl = _localop(H, l, k) L += qt.liouvillian(Hl, []) # Markovian Decay channels if c_ops_markov is not None: for c in c_ops_markov: cl = _localop(c, l, k) L += qt.liouvillian(None, [cl]) # Cascade coupling c1 = np.array([_localop(c, l, k) for c in L1]) c2 = np.array([_localop(c, l+1, k) for c in L2]) c2dag = np.array([c.dag() for c in c2]) Hcasc = -0.5j*np.dot(c2dag, np.dot(S, c1)) Hcasc += Hcasc.dag() Lvec = c2 + np.dot(S, c1) L += qt.liouvillian(Hcasc, [c for c in Lvec]) # last system L += qt.liouvillian(_localop(H, k, k), [_localop(c, k, k) for c in L1]) if c_ops_markov is not None: for c in c_ops_markov: cl = _localop(c, k, k) L += qt.liouvillian(None, [cl]) E0.dims = L.dims # return generator and identity superop E0 return L, E0
def jc_integrate(self, N, wc, wa, g, kappa, gamma, pump, psi0, use_rwa, tlist): # Hamiltonian a = tensor(destroy(N), identity(2)) sm = tensor(identity(N), destroy(2)) # Identity super-operator E0 = sprepost(tensor(qeye(N), qeye(2)), tensor(qeye(N), qeye(2))) if use_rwa: # use the rotating wave approxiation H = wc * a.dag() * a + wa * sm.dag() * sm + g * (a.dag() * sm + a * sm.dag()) else: H = wc * a.dag() * a + wa * sm.dag() * sm + g * (a.dag() + a) * ( sm + sm.dag()) # collapse operators c_op_list = [] n_th_a = 0.0 # zero temperature rate = kappa * (1 + n_th_a) c_op_list.append(np.sqrt(rate) * a) rate = kappa * n_th_a if rate > 0.0: c_op_list.append(np.sqrt(rate) * a.dag()) rate = gamma if rate > 0.0: c_op_list.append(np.sqrt(rate) * sm) rate = pump if rate > 0.0: c_op_list.append(np.sqrt(rate) * sm.dag()) # evolve and calculate expectation values output1 = mesolve(H, psi0, tlist, c_op_list, []) output2 = mesolve(H, E0, tlist, c_op_list, []) return output1, output2
def testMETDDecayAsFuncList(self): "mesolve: time-dependence as function list with super as init cond" me_error = 1e-6 N = 10 # number of basis states to consider a = destroy(N) H = a.dag() * a psi0 = basis(N, 9) # initial state rho0vec = operator_to_vector(psi0 * psi0.dag()) E0 = sprepost(qeye(N), qeye(N)) kappa = 0.2 # coupling to oscillator def sqrt_kappa(t, args): return np.sqrt(kappa * np.exp(-t)) c_op_list = [[a, sqrt_kappa]] tlist = np.linspace(0, 10, 100) out1 = mesolve(H, psi0, tlist, c_op_list, []) out2 = mesolve(H, E0, tlist, c_op_list, []) fid = self.fidelitycheck(out1, out2, rho0vec) assert_(max(abs(1.0 - fid)) < me_error, True)
def jc_integrate(self, N, wc, wa, g, kappa, gamma, pump, psi0, use_rwa, tlist): # Hamiltonian a = tensor(destroy(N), identity(2)) sm = tensor(identity(N), destroy(2)) # Identity super-operator E0 = sprepost(tensor(qeye(N), qeye(2)), tensor(qeye(N), qeye(2))) if use_rwa: # use the rotating wave approxiation H = wc * a.dag() * a + wa * sm.dag() * sm + g * (a.dag() * sm + a * sm.dag()) else: H = wc * a.dag() * a + wa * sm.dag() * sm + g * (a.dag() + a) * (sm + sm.dag()) # collapse operators c_op_list = [] n_th_a = 0.0 # zero temperature rate = kappa * (1 + n_th_a) c_op_list.append(np.sqrt(rate) * a) rate = kappa * n_th_a if rate > 0.0: c_op_list.append(np.sqrt(rate) * a.dag()) rate = gamma if rate > 0.0: c_op_list.append(np.sqrt(rate) * sm) rate = pump if rate > 0.0: c_op_list.append(np.sqrt(rate) * sm.dag()) # evolve and calculate expectation values output1 = mesolve(H, psi0, tlist, c_op_list, []) output2 = mesolve(H, E0, tlist, c_op_list, []) return output1, output2
def testMETDDecayAsFunc(self): "mesolve: time-dependence as function with super as init cond" N = 10 # number of basis states to consider a = destroy(N) H = a.dag() * a rho0 = ket2dm(basis(N, 9)) # initial state rho0vec = operator_to_vector(rho0) E0 = sprepost(qeye(N), qeye(N)) kappa = 0.2 # coupling to oscillator def Liouvillian_func(t, args): c = np.sqrt(kappa * np.exp(-t)) * a data = liouvillian(H, [c]).data return data tlist = np.linspace(0, 10, 100) args = {'kappa': kappa} out1 = mesolve(Liouvillian_func, rho0, tlist, [], [], args=args) out2 = mesolve(Liouvillian_func, E0, tlist, [], [], args=args) fid = self.fidelitycheck(out1, out2, rho0vec) assert_(max(abs(1.0 - fid)) < me_error, True)
def testMETDDecayAsFunc(self): "mesolve: time-dependence as function with super as init cond" N = 10 # number of basis states to consider a = destroy(N) H = a.dag() * a rho0 = ket2dm(basis(N, 9)) # initial state rho0vec = operator_to_vector(rho0) E0 = sprepost(qeye(N), qeye(N)) kappa = 0.2 # coupling to oscillator def Liouvillian_func(t, args): c = np.sqrt(kappa * np.exp(-t)) * a data = liouvillian(H, [c]).data return data tlist = np.linspace(0, 10, 100) args = {"kappa": kappa} out1 = mesolve(Liouvillian_func, rho0, tlist, [], [], args=args) out2 = mesolve(Liouvillian_func, E0, tlist, [], [], args=args) fid = self.fidelitycheck(out1, out2, rho0vec) assert_(max(abs(1.0 - fid)) < me_error, True)
def decoder(self, kraus=False): S = self.encoder(kraus=True) if kraus: return S.dag() else: return qt.sprepost(S.dag(), S)
def rcsolve(Hsys, psi0, tlist, e_ops, Q, wc, alpha, N, w_th, sparse=False, options=None): """ Function to solve for an open quantum system using the reaction coordinate (RC) model. Parameters ---------- Hsys: Qobj The system hamiltonian. psi0: Qobj Initial state of the system. tlist: List. Time over which system evolves. e_ops: list of :class:`qutip.Qobj` / callback function single Single operator or list of operators for which to evaluate expectation values. Q: Qobj The coupling between system and bath. wc: Float Cutoff frequency. alpha: Float Coupling strength. N: Integer Number of cavity fock states. w_th: Float Temperature. sparse: Boolean Optional argument to call the sparse eigenstates solver if needed. options : :class:`qutip.Options` With options for the solver. Returns ------- output: Result System evolution. """ if options is None: options = Options() dot_energy, dot_state = Hsys.eigenstates(sparse=sparse) deltaE = dot_energy[1] - dot_energy[0] if (w_th < deltaE / 2): warnings.warn("Given w_th might not provide accurate results") gamma = deltaE / (2 * np.pi * wc) wa = 2 * np.pi * gamma * wc # reaction coordinate frequency g = np.sqrt(np.pi * wa * alpha / 2.0) # reaction coordinate coupling nb = (1 / (np.exp(wa / w_th) - 1)) # Reaction coordinate hamiltonian/operators dimensions = dims(Q) a = tensor(destroy(N), qeye(dimensions[1])) unit = tensor(qeye(N), qeye(dimensions[1])) Nmax = N * dimensions[1][0] Q_exp = tensor(qeye(N), Q) Hsys_exp = tensor(qeye(N), Hsys) e_ops_exp = [tensor(qeye(N), kk) for kk in e_ops] na = a.dag() * a xa = a.dag() + a # decoupled Hamiltonian H0 = wa * a.dag() * a + Hsys_exp # interaction H1 = (g * (a.dag() + a) * Q_exp) H = H0 + H1 L = 0 PsipreEta = 0 PsipreX = 0 all_energy, all_state = H.eigenstates(sparse=sparse) Apre = spre((a + a.dag())) Apost = spost(a + a.dag()) for j in range(Nmax): for k in range(Nmax): A = xa.matrix_element(all_state[j].dag(), all_state[k]) delE = (all_energy[j] - all_energy[k]) if abs(A) > 0.0: if abs(delE) > 0.0: X = (0.5 * np.pi * gamma * (all_energy[j] - all_energy[k]) * (np.cosh( (all_energy[j] - all_energy[k]) / (2 * w_th)) / (np.sinh( (all_energy[j] - all_energy[k]) / (2 * w_th)))) * A) eta = (0.5 * np.pi * gamma * (all_energy[j] - all_energy[k]) * A) PsipreX = PsipreX + X * all_state[j] * all_state[k].dag() PsipreEta = PsipreEta + (eta * all_state[j] * all_state[k].dag()) else: X = 0.5 * np.pi * gamma * A * 2 * w_th PsipreX = PsipreX + X * all_state[j] * all_state[k].dag() A = a + a.dag() L = ((-spre(A * PsipreX)) + (sprepost(A, PsipreX)) + (sprepost(PsipreX, A)) + (-spost(PsipreX * A)) + (spre(A * PsipreEta)) + (sprepost(A, PsipreEta)) + (-sprepost(PsipreEta, A)) + (-spost(PsipreEta * A))) # Setup the operators and the Hamiltonian and the master equation # and solve for time steps in tlist rho0 = (tensor(thermal_dm(N, nb), psi0)) output = mesolve(H, rho0, tlist, [L], e_ops_exp, options=options) return output
def secular_term(state_j, state_k): jk = state_j*state_k.dag() kj = jk.dag() jj = state_j*state_j.dag() return 2*sprepost(kj, jk) - (spre(jj) + spost(jj))
def commutator_term2(O1, O2): # [rho*O1, O2] return spost(O1*O2)-sprepost(O2, O1)
def rcsolve(Hsys, psi0, tlist, e_ops, Q, wc, alpha, N, w_th, sparse=False, options=None): """ Function to solve for an open quantum system using the reaction coordinate (RC) model. Parameters ---------- Hsys: Qobj The system hamiltonian. psi0: Qobj Initial state of the system. tlist: List. Time over which system evolves. e_ops: list of :class:`qutip.Qobj` / callback function single Single operator or list of operators for which to evaluate expectation values. Q: Qobj The coupling between system and bath. wc: Float Cutoff frequency. alpha: Float Coupling strength. N: Integer Number of cavity fock states. w_th: Float Temperature. sparse: Boolean Optional argument to call the sparse eigenstates solver if needed. options : :class:`qutip.Options` With options for the solver. Returns ------- output: Result System evolution. """ if options is None: options = Options() dot_energy, dot_state = Hsys.eigenstates(sparse=sparse) deltaE = dot_energy[1] - dot_energy[0] if (w_th < deltaE/2): warnings.warn("Given w_th might not provide accurate results") gamma = deltaE / (2 * np.pi * wc) wa = 2 * np.pi * gamma * wc # reaction coordinate frequency g = np.sqrt(np.pi * wa * alpha / 2.0) # reaction coordinate coupling nb = (1 / (np.exp(wa/w_th) - 1)) # Reaction coordinate hamiltonian/operators dimensions = dims(Q) a = tensor(destroy(N), qeye(dimensions[1])) unit = tensor(qeye(N), qeye(dimensions[1])) Nmax = N * dimensions[1][0] Q_exp = tensor(qeye(N), Q) Hsys_exp = tensor(qeye(N), Hsys) e_ops_exp = [tensor(qeye(N), kk) for kk in e_ops] na = a.dag() * a xa = a.dag() + a # decoupled Hamiltonian H0 = wa * a.dag() * a + Hsys_exp # interaction H1 = (g * (a.dag() + a) * Q_exp) H = H0 + H1 L = 0 PsipreEta = 0 PsipreX = 0 all_energy, all_state = H.eigenstates(sparse=sparse) Apre = spre((a + a.dag())) Apost = spost(a + a.dag()) for j in range(Nmax): for k in range(Nmax): A = xa.matrix_element(all_state[j].dag(), all_state[k]) delE = (all_energy[j] - all_energy[k]) if abs(A) > 0.0: if abs(delE) > 0.0: X = (0.5 * np.pi * gamma*(all_energy[j] - all_energy[k]) * (np.cosh((all_energy[j] - all_energy[k]) / (2 * w_th)) / (np.sinh((all_energy[j] - all_energy[k]) / (2 * w_th)))) * A) eta = (0.5 * np.pi * gamma * (all_energy[j] - all_energy[k]) * A) PsipreX = PsipreX + X * all_state[j] * all_state[k].dag() PsipreEta = PsipreEta + (eta * all_state[j] * all_state[k].dag()) else: X = 0.5 * np.pi * gamma * A * 2 * w_th PsipreX = PsipreX + X * all_state[j] * all_state[k].dag() A = a + a.dag() L = ((-spre(A * PsipreX)) + (sprepost(A, PsipreX)) + (sprepost(PsipreX, A)) + (-spost(PsipreX * A)) + (spre(A * PsipreEta)) + (sprepost(A, PsipreEta)) + (-sprepost(PsipreEta, A)) + (-spost(PsipreEta * A))) # Setup the operators and the Hamiltonian and the master equation # and solve for time steps in tlist rho0 = (tensor(thermal_dm(N, nb), psi0)) output = mesolve(H, rho0, tlist, [L], e_ops_exp, options=options) return output