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)] Parameters ---------- Alist : list A list of Floquet-Markov master equation rate matrices. f_energies : array The Floquet energies. Returns ------- output : array The Floquet-Markov master equation tensor `R`. """ if isinstance(Alist, list): # Alist can be a list of rate matrices corresponding # to different operators that couple to the environment N, M = np.shape(Alist[0]) else: # or a simple rate matrix, in which case we put it in a list Alist = [Alist] N, M = np.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 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)] Parameters ---------- Alist : list A list of Floquet-Markov master equation rate matrices. f_energies : array The Floquet energies. Returns ------- output : array The Floquet-Markov master equation tensor `R`. """ if isinstance(Alist, list): # Alist can be a list of rate matrices corresponding # to different operators that couple to the environment N, M = np.shape(Alist[0]) else: # or a simple rate matrix, in which case we put it in a list Alist = [Alist] N, M = np.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 _generic_ode_solve(r, psi0, tlist, expt_ops, opt, state_vectorize, state_norm_func=None): """ Internal function for solving ODEs. """ # # prepare output array # n_tsteps = len(tlist) dt = tlist[1]-tlist[0] output = Odedata() output.solver = "mesolve" output.times = tlist if isinstance(expt_ops, types.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(np.zeros(n_tsteps)) else: output.expect.append(np.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; if state_norm_func: psi.data = state_vectorize(r.y) state_norm = state_norm_func(psi.data) psi.data = psi.data / state_norm r.set_initial_value(r.y/state_norm, r.t) else: 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: pass return output
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, options=None): """ Solve the dynamics for the system using the Floquet-Markov master equation. """ if options == None: opt = Odeoptions() else: opt=options 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(np.zeros(n_tsteps)) else: output.expect.append(np.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 np.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 tensor(*args): """Calculates the tensor product of input operators. Parameters ---------- args : array_like ``list`` or ``array`` of quantum objects for tensor product. Returns -------- obj : qobj A composite quantum object. Examples -------- >>> tensor([sigmax(), sigmax()]) Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = True Qobj data = [[ 0.+0.j 0.+0.j 0.+0.j 1.+0.j] [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j] [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j] [ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]] """ if not args: raise TypeError("Requires at least one input argument") num_args = len(args) step = 0 for n in range(num_args): if isinstance(args[n], Qobj): qos = args[n] if step == 0: dat = qos.data dim = qos.dims shp = qos.shape step = 1 else: dat = sp.kron(dat, qos.data, format='csr') #sparse Kronecker product dim = [dim[0] + qos.dims[0], dim[1] + qos.dims[1]] #append dimensions of Qobjs shp = [dat.shape[0], dat.shape[1]] #new shape of matrix elif isinstance( args[n], (list, ndarray)): #checks if input is list/array of Qobjs qos = args[n] items = len(qos) #number of inputs if not all([ isinstance(k, Qobj) for k in qos ]): #raise error if one of the inputs is not a quantum object raise TypeError("One of inputs is not a quantum object") if items == 1: # if only one Qobj, do nothing if step == 0: dat = qos[0].data dim = qos[0].dims shp = qos[0].shape step = 1 else: dat = sp.kron(dat, qos[0].data, format='csr') #sparse Kronecker product dim = [dim[0] + qos[0].dims[0], dim[1] + qos[0].dims[1] ] #append dimensions of Qobjs shp = [dat.shape[0], dat.shape[1]] #new shape of matrix elif items != 1: if step == 0: dat = qos[0].data dim = qos[0].dims shp = qos[0].shape step = 1 for k in range(items - 1): #cycle over all items dat = sp.kron(dat, qos[k + 1].data, format='csr') #sparse Kronecker product dim = [ dim[0] + qos[k + 1].dims[0], dim[1] + qos[k + 1].dims[1] ] #append dimensions of Qobjs shp = [dat.shape[0], dat.shape[1]] #new shape of matrix out = Qobj() out.data = dat out.dims = dim out.shape = shp if qutip.settings.auto_tidyup: return Qobj(out).tidyup() #returns tidy Qobj else: return Qobj(out)
def tensor(*args): """Calculates the tensor product of input operators. Parameters ---------- args : array_like ``list`` or ``array`` of quantum objects for tensor product. Returns -------- obj : qobj A composite quantum object. Examples -------- >>> tensor([sigmax(), sigmax()]) Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = True Qobj data = [[ 0.+0.j 0.+0.j 0.+0.j 1.+0.j] [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j] [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j] [ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]] """ if not args: raise TypeError("Requires at least one input argument") num_args=len(args) step=0 for n in range(num_args): if isinstance(args[n],Qobj): qos=args[n] if step==0: dat=qos.data dim=qos.dims shp=qos.shape step=1 else: dat=sp.kron(dat,qos.data, format='csr') #sparse Kronecker product dim=[dim[0]+qos.dims[0],dim[1]+qos.dims[1]] #append dimensions of Qobjs shp=[dat.shape[0],dat.shape[1]] #new shape of matrix elif isinstance(args[n],(list,ndarray)):#checks if input is list/array of Qobjs qos=args[n] items=len(qos) #number of inputs if not all([isinstance(k,Qobj) for k in qos]): #raise error if one of the inputs is not a quantum object raise TypeError("One of inputs is not a quantum object") if items==1:# if only one Qobj, do nothing if step==0: dat=qos[0].data dim=qos[0].dims shp=qos[0].shape step=1 else: dat=sp.kron(dat,qos[0].data, format='csr') #sparse Kronecker product dim=[dim[0]+qos[0].dims[0],dim[1]+qos[0].dims[1]] #append dimensions of Qobjs shp=[dat.shape[0],dat.shape[1]] #new shape of matrix elif items!=1: if step==0: dat=qos[0].data dim=qos[0].dims shp=qos[0].shape step=1 for k in range(items-1): #cycle over all items dat=sp.kron(dat,qos[k+1].data, format='csr') #sparse Kronecker product dim=[dim[0]+qos[k+1].dims[0],dim[1]+qos[k+1].dims[1]] #append dimensions of Qobjs shp=[dat.shape[0],dat.shape[1]] #new shape of matrix out=Qobj() out.data=dat out.dims=dim out.shape=shp if qutip.settings.auto_tidyup: return Qobj(out).tidyup() #returns tidy Qobj else: return Qobj(out)
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], options=None): """ Evolve the ODEs defined by Bloch-Redfield master equation. The Bloch-Redfield tensor can be calculated by the function :func:`bloch_redfield_tensor`. Parameters ---------- R : :class:`qutip.Qobj` Bloch-Redfield tensor. ekets : array of :class:`qutip.Qobj` Array of kets that make up a basis tranformation for the eigenbasis. rho0 : :class:`qutip.Qobj` Initial density matrix. tlist : *list* / *array* List of times for :math:`t`. e_ops : list of :class:`qutip.Qobj` / callback function List of operators for which to evaluate expectation values. options : :class:`qutip.Qdeoptions` Options for the ODE solver. Returns ------- output: :class:`qutip.Odedata` An instance of the class :class:`qutip.Odedata`, which contains either an *array* of expectation values for the times specified by `tlist`. """ if options == None: options = Odeoptions() options.nsteps = 2500 # if options.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 # 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(np.zeros(n_tsteps)) else: result_list.append(np.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=options.method, order=options.order, atol=options.atol, rtol=options.rtol, #nsteps=options.nsteps, #first_step=options.first_step, min_step=options.min_step, max_step=options.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=[], options=None): """ Evolve the ODEs defined by Bloch-Redfield master equation. The Bloch-Redfield tensor can be calculated by the function :func:`bloch_redfield_tensor`. Parameters ---------- R : :class:`qutip.Qobj` Bloch-Redfield tensor. ekets : array of :class:`qutip.Qobj` Array of kets that make up a basis tranformation for the eigenbasis. rho0 : :class:`qutip.Qobj` Initial density matrix. tlist : *list* / *array* List of times for :math:`t`. e_ops : list of :class:`qutip.Qobj` / callback function List of operators for which to evaluate expectation values. options : :class:`qutip.Qdeoptions` Options for the ODE solver. Returns ------- output: :class:`qutip.Odedata` An instance of the class :class:`qutip.Odedata`, which contains either an *array* of expectation values for the times specified by `tlist`. """ if options == None: options = Odeoptions() options.nsteps = 2500 # if options.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 # 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(np.zeros(n_tsteps)) else: result_list.append(np.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=options.method, order=options.order, atol=options.atol, rtol=options.rtol, #nsteps=options.nsteps, #first_step=options.first_step, min_step=options.min_step, max_step=options.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 _generic_ode_solve(r, psi0, tlist, expt_ops, opt, state_vectorize, state_norm_func=None): """ Internal function for solving ODEs. """ # # prepare output array # n_tsteps = len(tlist) dt = tlist[1] - tlist[0] output = Odedata() output.solver = "mesolve" output.times = tlist if isinstance(expt_ops, types.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(np.zeros(n_tsteps)) else: output.expect.append(np.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 if state_norm_func: psi.data = state_vectorize(r.y) state_norm = state_norm_func(psi.data) psi.data = psi.data / state_norm r.set_initial_value(r.y / state_norm, r.t) else: 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: pass return output
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, options=None): """ Solve the dynamics for the system using the Floquet-Markov master equation. """ if options == None: opt = Odeoptions() else: opt = options 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(np.zeros(n_tsteps)) else: output.expect.append(np.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 np.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