def floquet_master_equation_tensor(Alist, f_energies): """ Construct a tensor that represents the master equation in the floquet basis (with constant Hamiltonian and collapse operators). Simplest RWA approximation [Grifoni et al, Phys.Rep. 304 229 (1998)] """ if isinstance(Alist, list): # Alist can be a list of rate matrices corresponding # to different operators that couple to the environment N, M = shape(Alist[0]) else: # or a simple rate matrix, in which case we put it in a list Alist = [Alist] N, M = shape(Alist[0]) R = Qobj(scipy.sparse.csr_matrix((N * N, N * N)), [[N, N], [N, N]], [N * N, N * N]) R.data = R.data.tolil() for I in range(N * N): a, b = vec2mat_index(N, I) for J in range(N * N): c, d = vec2mat_index(N, J) R.data[I, J] = -1.0j * (f_energies[a] - f_energies[b]) * (a == c) * (b == d) for A in Alist: s1 = s2 = 0 for n in range(N): s1 += A[a, n] * (n == c) * (n == d) - A[n, a] * ( a == c) * (a == d) s2 += (A[n, a] + A[n, b]) * (a == c) * (b == d) dR = (a == b) * s1 - 0.5 * (1 - (a == b)) * s2 if dR != 0.0: R.data[I, J] += dR R.data = R.data.tocsr() return R
def liouvillian_fast(H, c_op_list): """Assembles the Liouvillian superoperator from a Hamiltonian and a ``list`` of collapse operators. Like liouvillian, but with an experimental implementation which avoids creating extra Qobj instances, which can be advantageous for large systems. Parameters ---------- H : qobj System Hamiltonian. c_op_list : array_like A ``list`` or ``array`` of collpase operators. Returns ------- L : qobj Louvillian superoperator. .. note:: Experimental. """ d = H.dims[1] L = Qobj() L.dims = [[H.dims[0][:], d[:]], [H.dims[1][:], d[:]]] L.shape = [prod(L.dims[0][0]) * prod(L.dims[0][1]), prod(L.dims[1][0]) * prod(L.dims[1][1])] L.data = -1j * ( sp.kron(sp.identity(prod(d)), H.data, format="csr") - sp.kron(H.data.T, sp.identity(prod(d)), format="csr") ) n_op = len(c_op_list) for m in range(0, n_op): L.data = L.data + sp.kron(sp.identity(prod(d)), c_op_list[m].data, format="csr") * sp.kron( c_op_list[m].data.T.conj().T, sp.identity(prod(d)), format="csr" ) cdc = c_op_list[m].data.T.conj() * c_op_list[m].data L.data = L.data - 0.5 * sp.kron(sp.identity(prod(d)), cdc, format="csr") L.data = L.data - 0.5 * sp.kron(cdc.T, sp.identity(prod(d)), format="csr") return L
def floquet_master_equation_tensor(Alist, f_energies): """ Construct a tensor that represents the master equation in the floquet basis (with constant Hamiltonian and collapse operators). Simplest RWA approximation [Grifoni et al, Phys.Rep. 304 229 (1998)] """ if isinstance(Alist, list): # Alist can be a list of rate matrices corresponding # to different operators that couple to the environment N, M = shape(Alist[0]) else: # or a simple rate matrix, in which case we put it in a list Alist = [Alist] N, M = shape(Alist[0]) R = Qobj(scipy.sparse.csr_matrix((N*N,N*N)), [[N,N], [N,N]], [N*N,N*N]) R.data=R.data.tolil() for I in range(N*N): a,b = vec2mat_index(N, I) for J in range(N*N): c,d = vec2mat_index(N, J) R.data[I,J] = - 1.0j * (f_energies[a]-f_energies[b]) * (a == c) * (b == d) for A in Alist: s1 = s2 = 0 for n in range(N): s1 += A[a,n] * (n == c) * (n == d) - A[n,a] * (a == c) * (a == d) s2 += (A[n,a] + A[n,b]) * (a == c) * (b == d) dR = (a == b) * s1 - 0.5 * (1 - (a == b)) * s2 if dR != 0.0: R.data[I,J] += dR R.data=R.data.tocsr() return R
def liouvillian_fast(H, c_op_list): """Assembles the Liouvillian superoperator from a Hamiltonian and a ``list`` of collapse operators. Like liouvillian, but with an experimental implementation which avoids creating extra Qobj instances, which can be advantageous for large systems. Parameters ---------- H : qobj System Hamiltonian. c_op_list : array_like A ``list`` or ``array`` of collpase operators. Returns ------- L : qobj Louvillian superoperator. .. note:: Experimental. """ d=H.dims[1] L=Qobj() L.dims=[[H.dims[0][:],d[:]],[H.dims[1][:],d[:]]] L.shape=[prod(L.dims[0][0])*prod(L.dims[0][1]),prod(L.dims[1][0])*prod(L.dims[1][1])] L.data = -1j *(sp.kron(sp.identity(prod(d)), H.data,format='csr') - sp.kron(H.data.T,sp.identity(prod(d)),format='csr')) n_op = len(c_op_list) for m in range(0, n_op): L.data = L.data + sp.kron(sp.identity(prod(d)), c_op_list[m].data,format='csr') * sp.kron(c_op_list[m].data.T.conj().T,sp.identity(prod(d)),format='csr') cdc = c_op_list[m].data.T.conj()*c_op_list[m].data L.data = L.data - 0.5 * sp.kron(sp.identity(prod(d)), cdc,format='csr') L.data = L.data - 0.5 * sp.kron(cdc.T,sp.identity(prod(d)),format='csr') return L
def photon_dist(rho): """return diagonals of photon density matrix""" from operators import vector_to_operator from qutip import Qobj, ptrace from basis import ldim_p, ldim_s rho_small = convert_rho.dot(rho) rho_small = vector_to_operator(rho_small) rho_q = Qobj() rho_q.data = rho_small rho_q.dims = [[ldim_p, ldim_s], [ldim_p, ldim_s]] rho_q = ptrace(rho_q, 0) pops = rho_q.data.diagonal() return pops
def spost(A): """Superoperator formed from post-multiplication by operator A Parameters ---------- A : qobj Quantum operator for post multiplication. Returns ------- super : qobj Superoperator formed from input qauntum object. """ if not isoper(A): raise TypeError('Input is not a quantum object') d=A.dims[0] S=Qobj() S.dims=[[d[:],A.dims[1][:]],[d[:],A.dims[0][:]]] S.shape=[prod(S.dims[0][0])*prod(S.dims[0][1]),prod(S.dims[1][0])*prod(S.dims[1][1])] S.data=sp.kron(A.data.T,sp.identity(prod(d))) return Qobj(S)
def spre(A): """Superoperator formed from pre-multiplication by operator A. Parameters ---------- A : qobj Quantum operator for pre-multiplication. Returns -------- super :qobj Superoperator formed from input quantum object. """ if not isoper(A): raise TypeError('Input is not a quantum object') d=A.dims[1] S=Qobj() S.dims=[[A.dims[0][:],d[:]],[A.dims[1][:],d[:]]] S.shape=[prod(S.dims[0][0])*prod(S.dims[0][1]),prod(S.dims[1][0])*prod(S.dims[1][1])] S.data=sp.kron(sp.identity(prod(d)),A.data,format='csr') return S
def wigner_comp(rho, xvec, yvec): """calculate wigner function of central site from density matrix rho at a grid of points defined by xvec and yvec""" global convert_rho from operators import expect, vector_to_operator from qutip import Qobj, wigner, ptrace from basis import ldim_p, ldim_s rho_small = convert_rho.dot(rho) rho_small = vector_to_operator(rho_small) rho_q = Qobj() rho_q.data = rho_small rho_q.dims = [[ldim_p, ldim_s], [ldim_p, ldim_s]] rho_q = ptrace(rho_q, 0) w = wigner(rho_q, xvec, yvec) return w
def spre(A): """Superoperator formed from pre-multiplication by operator A. Parameters ---------- A : qobj Quantum operator for pre-multiplication. Returns -------- super :qobj Superoperator formed from input quantum object. """ if not isoper(A): raise TypeError("Input is not a quantum object") d = A.dims[1] S = Qobj() S.dims = [[A.dims[0][:], d[:]], [A.dims[1][:], d[:]]] S.shape = [prod(S.dims[0][0]) * prod(S.dims[0][1]), prod(S.dims[1][0]) * prod(S.dims[1][1])] S.data = sp.kron(sp.identity(prod(d)), A.data, format="csr") return S
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, opt=None): """ Solve the dynamics for the system using the Floquet-Markov master equation. """ if opt == None: opt = Odeoptions() if opt.tidy: R.tidyup() # # check initial state # if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # prepare output array # n_tsteps = len(tlist) dt = tlist[1]-tlist[0] output = Odedata() output.times = tlist if isinstance(e_ops, FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(e_ops, list): n_expt_op = len(e_ops) expt_callback = False if n_expt_op == 0: output.states = [] else: output.expect = [] output.num_expect = n_expt_op for op in e_ops: if op.isherm: output.expect.append(zeros(n_tsteps)) else: output.expect.append(zeros(n_tsteps,dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # transform the initial density matrix and the e_ops opterators to the # eigenbasis: from computational basis to the floquet basis # if ekets != None: rho0 = rho0.transform(ekets, True) if isinstance(e_ops, list): for n in arange(len(e_ops)): # not working e_ops[n] = e_ops[n].transform(ekets) # # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(cyq_ode_rhs) r.set_f_params(R.data.data, R.data.indices, R.data.indptr) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) # # start evolution # rho = Qobj(rho0) t_idx = 0 for t in tlist: if not r.successful(): break; rho.data = vec2mat(r.y) if expt_callback: # use callback method e_ops(t, Qobj(rho)) else: # calculate all the expectation values, or output rho if no operators if n_expt_op == 0: output.states.append(Qobj(rho)) # copy psi/rho else: for m in range(0, n_expt_op): output.expect[m][t_idx] = expect(e_ops[m], rho) # basis OK? r.integrate(r.t + dt) t_idx += 1 return output
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], opt=None): """ Evolve the ODEs defined by Bloch-Redfeild master equation. """ if opt == None: opt = Odeoptions() opt.nsteps = 2500 # if opt.tidy: R.tidyup() # # check initial state # if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = rho0 * rho0.dag() # # prepare output array # m n_e_ops = len(e_ops) n_tsteps = len(tlist) dt = tlist[1] - tlist[0] if n_e_ops == 0: result_list = [] else: result_list = [] for op in e_ops: if op.isherm and rho0.isherm: result_list.append(zeros(n_tsteps)) else: result_list.append(zeros(n_tsteps, dtype=complex)) # # transform the initial density matrix and the e_ops opterators to the # eigenbasis # if ekets != None: rho0 = rho0.transform(ekets) for n in arange(len(e_ops)): e_ops[n] = e_ops[n].transform(ekets, False) # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(cyq_ode_rhs) r.set_f_params(R.data.data, R.data.indices, R.data.indptr) r.set_integrator( 'zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, #nsteps=opt.nsteps, #first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) # # start evolution # rho = Qobj(rho0) t_idx = 0 for t in tlist: if not r.successful(): break rho.data = vec2mat(r.y) # calculate all the expectation values, or output rho if no operators if n_e_ops == 0: result_list.append(Qobj(rho)) else: for m in range(0, n_e_ops): result_list[m][t_idx] = expect(e_ops[m], rho) r.integrate(r.t + dt) t_idx += 1 return result_list
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], opt=None): """ Evolve the ODEs defined by Bloch-Redfeild master equation. """ if opt == None: opt = Odeoptions() opt.nsteps = 2500 # if opt.tidy: R.tidyup() # # check initial state # if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = rho0 * rho0.dag() # # prepare output array # m n_e_ops = len(e_ops) n_tsteps = len(tlist) dt = tlist[1]-tlist[0] if n_e_ops == 0: result_list = [] else: result_list = [] for op in e_ops: if op.isherm and rho0.isherm: result_list.append(zeros(n_tsteps)) else: result_list.append(zeros(n_tsteps,dtype=complex)) # # transform the initial density matrix and the e_ops opterators to the # eigenbasis # if ekets != None: rho0 = rho0.transform(ekets) for n in arange(len(e_ops)): e_ops[n] = e_ops[n].transform(ekets, False) # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(cyq_ode_rhs) r.set_f_params(R.data.data, R.data.indices, R.data.indptr) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, #nsteps=opt.nsteps, #first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) # # start evolution # rho = Qobj(rho0) t_idx = 0 for t in tlist: if not r.successful(): break; rho.data = vec2mat(r.y) # calculate all the expectation values, or output rho if no operators if n_e_ops == 0: result_list.append(Qobj(rho)) else: for m in range(0, n_e_ops): result_list[m][t_idx] = expect(e_ops[m], rho) r.integrate(r.t + dt) t_idx += 1 return result_list
def steady(L,maxiter=100,tol=1e-6,method='solve'): """Steady state for the evolution subject to the supplied Louvillian. Parameters ---------- L : qobj Liouvillian superoperator. maxiter : int Maximum number of iterations to perform, default = 100. tol : float Tolerance used by iterative solver, default = 1e-6. method : str Method for solving linear equations. Direct solver 'solve' (default) or iterative biconjugate gradient method 'bicg'. Returns -------- ket : qobj Ket vector for steady state. Notes ----- Uses the inverse power method. See any Linear Algebra book with an iterative methods section. """ eps=finfo(float).eps if (not isoper(L)) & (not issuper(L)): raise TypeError('Steady states can only be found for operators or superoperators.') rhoss=Qobj() sflag=issuper(L) if sflag: rhoss.dims=L.dims[0] rhoss.shape=[prod(rhoss.dims[0]),prod(rhoss.dims[1])] else: rhoss.dims=[L.dims[0],1] rhoss.shape=[prod(rhoss.dims[0]),1] n=prod(rhoss.shape) L1=L.data+eps*_sp_inf_norm(L)*sp.eye(n,n,format='csr') v=randn(n,1) it=0 while (la.norm(L.data*v,np.inf)>tol) and (it<maxiter): if method=='bicg': v,check=bicg(L1,v,tol=tol) else: v=spsolve(L1,v,use_umfpack=False) v=v/la.norm(v,np.inf) it+=1 if it>=maxiter: raise ValueError('Failed to find steady state after ' + str(maxiter) +' iterations') #normalise according to type of problem if sflag: trow=sp.eye(rhoss.shape[0],rhoss.shape[0],format='lil') trow=trow.reshape((1,n)).tocsr() data=v/sum(trow.dot(v)) else: data=data/la.norm(v) data=reshape(data,(rhoss.shape[0],rhoss.shape[1])).T data=sp.csr_matrix(data) rhoss.data=0.5*(data+data.conj().T) #data=sp.triu(data,format='csr')#take only upper triangle #rhoss.data=0.5*sp.eye(rhoss.shape[0],rhoss.shape[1],format='csr')*(data+data.conj().T) #output should be hermitian, but not guarenteed using iterative meth if qset.auto_tidyup: return Qobj(rhoss).tidyup() else: return Qobj(rhoss)
def steady(L, maxiter=100, tol=1e-6, method='solve'): """Steady state for the evolution subject to the supplied Louvillian. Parameters ---------- L : qobj Liouvillian superoperator. maxiter : int Maximum number of iterations to perform, default = 100. tol : float Tolerance used by iterative solver, default = 1e-6. method : str Method for solving linear equations. Direct solver 'solve' (default) or iterative biconjugate gradient method 'bicg'. Returns -------- ket : qobj Ket vector for steady state. Notes ----- Uses the inverse power method. See any Linear Algebra book with an iterative methods section. """ eps = finfo(float).eps if (not isoper(L)) & (not issuper(L)): raise TypeError( 'Steady states can only be found for operators or superoperators.') rhoss = Qobj() sflag = issuper(L) if sflag: rhoss.dims = L.dims[0] rhoss.shape = [prod(rhoss.dims[0]), prod(rhoss.dims[1])] else: rhoss.dims = [L.dims[0], 1] rhoss.shape = [prod(rhoss.dims[0]), 1] n = prod(rhoss.shape) L1 = L.data + eps * sp_inf_norm(L) * sp.eye(n, n, format='csr') v = randn(n, 1) it = 0 while (la.norm(L.data * v, inf) > tol) and (it < maxiter): if method == 'bicg': v, check = bicg(L1, v, tol=tol) else: v = spsolve(L1, v, use_umfpack=False) v = v / la.norm(v, inf) it += 1 if it >= maxiter: raise ValueError('Failed to find steady state after ' + str(maxiter) + ' iterations') #normalise according to type of problem if sflag: trow = sp.eye(rhoss.shape[0], rhoss.shape[0], format='lil') trow = trow.reshape((1, n)).tocsr() data = v / sum(trow.dot(v)) else: data = data / la.norm(v) data = reshape(data, (rhoss.shape[0], rhoss.shape[1])).T data = sp.csr_matrix(data) rhoss.data = 0.5 * (data + data.conj().T) #data=sp.triu(data,format='csr')#take only upper triangle #rhoss.data=0.5*sp.eye(rhoss.shape[0],rhoss.shape[1],format='csr')*(data+data.conj().T) #output should be hermitian, but not guarenteed using iterative meth if qset.auto_tidyup: return Qobj(rhoss).tidyup() else: return Qobj(rhoss)
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, opt=None): """ Solve the dynamics for the system using the Floquet-Markov master equation. """ if opt == None: opt = Odeoptions() if opt.tidy: R.tidyup() # # check initial state # if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # prepare output array # n_tsteps = len(tlist) dt = tlist[1] - tlist[0] output = Odedata() output.times = tlist if isinstance(e_ops, FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(e_ops, list): n_expt_op = len(e_ops) expt_callback = False if n_expt_op == 0: output.states = [] else: output.expect = [] output.num_expect = n_expt_op for op in e_ops: if op.isherm: output.expect.append(zeros(n_tsteps)) else: output.expect.append(zeros(n_tsteps, dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # transform the initial density matrix and the e_ops opterators to the # eigenbasis: from computational basis to the floquet basis # if ekets != None: rho0 = rho0.transform(ekets, True) if isinstance(e_ops, list): for n in arange(len(e_ops)): # not working e_ops[n] = e_ops[n].transform(ekets) # # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(cyq_ode_rhs) r.set_f_params(R.data.data, R.data.indices, R.data.indptr) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) # # start evolution # rho = Qobj(rho0) t_idx = 0 for t in tlist: if not r.successful(): break rho.data = vec2mat(r.y) if expt_callback: # use callback method e_ops(t, Qobj(rho)) else: # calculate all the expectation values, or output rho if no operators if n_expt_op == 0: output.states.append(Qobj(rho)) # copy psi/rho else: for m in range(0, n_expt_op): output.expect[m][t_idx] = expect(e_ops[m], rho) # basis OK? r.integrate(r.t + dt) t_idx += 1 return output
def generic_ode_solve(r, psi0, tlist, expt_ops, opt, state_vectorize): """ Internal function for solving ODEs. """ # # prepare output array # n_tsteps = len(tlist) dt = tlist[1]-tlist[0] output = Odedata() output.times = tlist if isinstance(expt_ops, FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(expt_ops, list): n_expt_op = len(expt_ops) expt_callback = False if n_expt_op == 0: output.states = [] else: output.expect = [] output.num_expect = n_expt_op for op in expt_ops: if op.isherm and psi0.isherm: output.expect.append(zeros(n_tsteps)) else: output.expect.append(zeros(n_tsteps,dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # start evolution # psi = Qobj(psi0) t_idx = 0 for t in tlist: if not r.successful(): break; psi.data = state_vectorize(r.y) if expt_callback: # use callback method expt_ops(t, Qobj(psi)) else: # calculate all the expectation values, or output rho if no operators if n_expt_op == 0: output.states.append(Qobj(psi)) # copy psi/rho else: for m in range(0, n_expt_op): output.expect[m][t_idx] = expect(expt_ops[m], psi) r.integrate(r.t + dt) t_idx += 1 if not opt.rhs_reuse and odeconfig.tdname != None: try: os.remove(odeconfig.tdname+".pyx") except: print('Error removing '+str(odeconfig.tdname)+".pyx file") pass return output
def generic_ode_solve(r, psi0, tlist, expt_ops, opt, state_vectorize): """ Internal function for solving ODEs. """ # # prepare output array # n_tsteps = len(tlist) dt = tlist[1] - tlist[0] output = Odedata() output.times = tlist if isinstance(expt_ops, FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(expt_ops, list): n_expt_op = len(expt_ops) expt_callback = False if n_expt_op == 0: output.states = [] else: output.expect = [] output.num_expect = n_expt_op for op in expt_ops: if op.isherm and psi0.isherm: output.expect.append(zeros(n_tsteps)) else: output.expect.append(zeros(n_tsteps, dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # start evolution # psi = Qobj(psi0) t_idx = 0 for t in tlist: if not r.successful(): break psi.data = state_vectorize(r.y) if expt_callback: # use callback method expt_ops(t, Qobj(psi)) else: # calculate all the expectation values, or output rho if no operators if n_expt_op == 0: output.states.append(Qobj(psi)) # copy psi/rho else: for m in range(0, n_expt_op): output.expect[m][t_idx] = expect(expt_ops[m], psi) r.integrate(r.t + dt) t_idx += 1 if not opt.rhs_reuse and odeconfig.tdname != None: try: os.remove(odeconfig.tdname + ".pyx") except: print('Error removing ' + str(odeconfig.tdname) + ".pyx file") pass return output