def _mesolve_list_td(H_func, rho0, tlist, c_op_list, e_ops, args, opt, progress_bar): """! Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fall back on the unitary schrodinger equation solver if len(c_op_list) == 0: return _sesolve_list_td(H_func, rho0, tlist, e_ops, args, opt) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if not isinstance(H_func[0], (list, np.ndarray)) or len(H_func[0]) <= 1: raise TypeError('Time-dependent Hamiltonians must be a list ' + 'with two or more terms') if (not isinstance(H_func[1], (list, np.ndarray))) or \ (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError('Time-dependent coefficients must be list with ' + 'length N-1 where N is the number of ' + 'Hamiltonian terms.') if opt.rhs_reuse and odeconfig.tdfunc is None: rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian_fast(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian_fast(H_func[0][m], [])) # create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += ("Ldata[%d], Linds[%d], Lptrs[%d]," % (k, k, k)) if args: td_consts = args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") # run code generator if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(odeconfig.tdfunc) 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]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
def _sesolve_list_str_td(H_list, psi0, tlist, expt_ops, args, opt): """ Internal function for solving the master equation. See mesolve for usage. """ if debug: print(inspect.stack()[0][3]) # # check initial state: must be a density matrix # if not isket(psi0): raise TypeError("The unitary solver requires a ket as initial state") # # construct liouvillian # Ldata = [] Linds = [] Lptrs = [] Lcoeff = [] # loop over all hamiltonian terms, convert to superoperator form and # add the data of sparse matrix representation to h_coeff for h_spec in H_list: if isinstance(h_spec, Qobj): h = h_spec h_coeff = "1.0" elif isinstance(h_spec, list): h = h_spec[0] h_coeff = h_spec[1] else: raise TypeError("Incorrect specification of time-dependent " + "Hamiltonian (expected string format)") L = -1j * h Ldata.append(L.data.data) Linds.append(L.data.indices) Lptrs.append(L.data.indptr) Lcoeff.append(h_coeff) # the total number of liouvillian terms (hamiltonian terms + # collapse operators) n_L_terms = len(Ldata) # # setup ode args string: we expand the list Ldata, Linds and Lptrs into # and explicit list of parameters # string_list = [] for k in range(n_L_terms): string_list.append("Ldata[" + str(k) + "],Linds[" + str(k) + "],Lptrs[" + str(k) + "]") for name, value in args.items(): string_list.append(str(value)) parameter_string = ",".join(string_list) # # generate and compile new cython code if necessary # if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = psi0.full() r = scipy.integrate.ode(odeconfig.tdfunc) 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]) code = compile('r.set_f_params(' + parameter_string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, psi0, tlist, expt_ops, opt, lambda x: x)
def _mesolve_list_str_td(H_list, rho0, tlist, c_list, e_ops, args, opt, progress_bar): """ Internal function for solving the master equation. See mesolve for usage. """ if debug: print(inspect.stack()[0][3]) # # check initial state: must be a density matrix # if isket(rho0): rho0 = rho0 * rho0.dag() # # construct liouvillian # Lconst = 0 Ldata = [] Linds = [] Lptrs = [] Lcoeff = [] # loop over all hamiltonian terms, convert to superoperator form and # add the data of sparse matrix representation to for h_spec in H_list: if isinstance(h_spec, Qobj): h = h_spec if isoper(h): Lconst += -1j * (spre(h) - spost(h)) elif issuper(h): Lconst += h else: raise TypeError("Incorrect specification of time-dependent " + "Hamiltonian (expected operator or " + "superoperator)") elif isinstance(h_spec, list): h = h_spec[0] h_coeff = h_spec[1] if isoper(h): L = -1j * (spre(h) - spost(h)) elif issuper(h): L = h else: raise TypeError("Incorrect specification of time-dependent " + "Hamiltonian (expected operator or " + "superoperator)") Ldata.append(L.data.data) Linds.append(L.data.indices) Lptrs.append(L.data.indptr) Lcoeff.append(h_coeff) else: raise TypeError("Incorrect specification of time-dependent " + "Hamiltonian (expected string format)") # loop over all collapse operators for c_spec in c_list: if isinstance(c_spec, Qobj): c = c_spec if isoper(c): cdc = c.dag() * c Lconst += spre(c) * spost(c.dag()) - 0.5 * spre(cdc) \ - 0.5 * spost(cdc) elif issuper(c): Lconst += c else: raise TypeError("Incorrect specification of time-dependent " + "Liouvillian (expected operator or " + "superoperator)") elif isinstance(c_spec, list): c = c_spec[0] c_coeff = c_spec[1] if isoper(c): cdc = c.dag() * c L = spre(c) * spost(c.dag()) - 0.5 * spre(cdc) \ - 0.5 * spost(cdc) c_coeff = "(" + c_coeff + ")**2" elif issuper(c): L = c else: raise TypeError("Incorrect specification of time-dependent " + "Liouvillian (expected operator or " + "superoperator)") Ldata.append(L.data.data) Linds.append(L.data.indices) Lptrs.append(L.data.indptr) Lcoeff.append(c_coeff) else: raise TypeError("Incorrect specification of time-dependent " + "collapse operators (expected string format)") # add the constant part of the lagrangian if Lconst != 0: Ldata.append(Lconst.data.data) Linds.append(Lconst.data.indices) Lptrs.append(Lconst.data.indptr) Lcoeff.append("1.0") # the total number of liouvillian terms (hamiltonian terms + # collapse operators) n_L_terms = len(Ldata) # # setup ode args string: we expand the list Ldata, Linds and Lptrs into # and explicit list of parameters # string_list = [] for k in range(n_L_terms): string_list.append("Ldata[%d], Linds[%d], Lptrs[%d]" % (k, k, k)) for name, value in args.items(): string_list.append(str(value)) parameter_string = ",".join(string_list) # # generate and compile new cython code if necessary # if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(odeconfig.tdfunc) 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]) code = compile('r.set_f_params(' + parameter_string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
def _sesolve_list_td(H_func, psi0, tlist, e_ops, args, opt, progress_bar): """! Evolve the wave function using an ODE solver with time-dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) if not isket(psi0): raise TypeError("psi0 must be a ket") # # configure time-dependent terms and setup ODE solver # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if (not isinstance(H_func[0], (list, np.ndarray))) or \ (len(H_func[0]) <= 1): raise TypeError( 'Time-dependent Hamiltonians must be a list with two ' + 'or more terms') if (not isinstance(H_func[1], (list, np.ndarray))) or \ (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError('Time-dependent coefficients must be list with ' + 'length N-1 where N is the number of ' + 'Hamiltonian terms.') tflag = 1 if opt.rhs_reuse and odeconfig.tdfunc is None: print("No previous time-dependent RHS found.") print("Generating one for you...") rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] # create data arrays for time-dependent RHS function Hdata = [-1.0j * H_func[0][k].data.data for k in range(lenh)] Hinds = [H_func[0][k].data.indices for k in range(lenh)] Hptrs = [H_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += ("Hdata[" + str(k) + "],Hinds[" + str(k) + "],Hptrs[" + str(k) + "],") if args: td_consts = args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") # run code generator if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = psi0.full().ravel() r = scipy.integrate.ode(odeconfig.tdfunc) 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]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, psi0, tlist, e_ops, opt, progress_bar, dims=psi0.dims)
def rhs_generate(H, c_ops, args={}, options=Odeoptions(), name=None): """ Generates the Cython functions needed for solving the dynamics of a given system using the mesolve function inside a parfor loop. Parameters ---------- H : qobj System Hamiltonian. c_ops : list ``list`` of collapse operators. args : dict Arguments for time-dependent Hamiltonian and collapse operator terms. options : Odeoptions Instance of ODE solver options. name: str Name of generated RHS Notes ----- Using this function with any solver other than the mesolve function will result in an error. """ odeconfig.reset() odeconfig.options = options if name: odeconfig.tdname = name else: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) Lconst = 0 Ldata = [] Linds = [] Lptrs = [] Lcoeff = [] # loop over all hamiltonian terms, convert to superoperator form and # add the data of sparse matrix represenation to for h_spec in H: if isinstance(h_spec, Qobj): h = h_spec Lconst += -1j * (spre(h) - spost(h)) elif isinstance(h_spec, list): h = h_spec[0] h_coeff = h_spec[1] L = -1j * (spre(h) - spost(h)) Ldata.append(L.data.data) Linds.append(L.data.indices) Lptrs.append(L.data.indptr) Lcoeff.append(h_coeff) else: raise TypeError("Incorrect specification of time-dependent " + "Hamiltonian (expected string format)") # loop over all collapse operators for c_spec in c_ops: if isinstance(c_spec, Qobj): c = c_spec cdc = c.dag() * c Lconst += spre(c) * spost( c.dag()) - 0.5 * spre(cdc) - 0.5 * spost(cdc) elif isinstance(c_spec, list): c = c_spec[0] c_coeff = c_spec[1] cdc = c.dag() * c L = spre(c) * spost(c.dag()) - 0.5 * spre(cdc) - 0.5 * spost(cdc) Ldata.append(L.data.data) Linds.append(L.data.indices) Lptrs.append(L.data.indptr) Lcoeff.append("(" + c_coeff + ")**2") else: raise TypeError("Incorrect specification of time-dependent " + "collapse operators (expected string format)") # add the constant part of the lagrangian if Lconst != 0: Ldata.append(Lconst.data.data) Linds.append(Lconst.data.indices) Lptrs.append(Lconst.data.indptr) Lcoeff.append("1.0") # the total number of liouvillian terms (hamiltonian terms + collapse # operators) n_L_terms = len(Ldata) cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code) odeconfig.tdfunc = cyq_td_ode_rhs try: os.remove(odeconfig.tdname + ".pyx") except: pass
def _mesolve_list_td(H_func, rho0, tlist, c_op_list, expt_ops, H_args, opt): """! Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ n_op = len(c_op_list) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fallback on the unitary schrodinger equation solver if n_op == 0: return _wfsolve_list_td(H_func, rho0, tlist, expt_ops, H_args, opt) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if (not isinstance(H_func[0], (list, ndarray))) or (len(H_func[0]) <= 1): raise TypeError( 'Time-dependent Hamiltonians must be a list with two or more terms' ) if (not isinstance(H_func[1], (list, ndarray))) or (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError( 'Time-dependent coefficients must be list with length ' + 'N-1 where N is the number of Hamiltonian terms.') if opt.rhs_reuse == True and odeconfig.tdfunc == None: print("No previous time-dependent RHS found.") print("Generating one for you...") rhs_generate(H_func, H_args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian(H_func[0][m], [])) #create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] #setup ode args string string = "" for k in range(lenh): string += "Ldata[" + str(k) + "],Linds[" + str(k) + "],Lptrs[" + str( k) + "]," if H_args: td_consts = H_args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") #run code generator if not opt.rhs_reuse or odeconfig.tdfunc == None: if opt.rhs_filename == None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args) cgen.generate(odeconfig.tdname + ".pyx") os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs': [numpy.get_include()]}) code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(odeconfig.tdfunc) 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]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, expt_ops, opt, vec2mat)
def _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options): """Creates the appropriate data structures for the monte carlo solver based on the given time-dependent, or indepdendent, format. """ #take care of expectation values, if any if any(e_ops): odeconfig.e_num = len(e_ops) for op in e_ops: if isinstance(op, list): op = op[0] odeconfig.e_ops_data.append(op.data.data) odeconfig.e_ops_ind.append(op.data.indices) odeconfig.e_ops_ptr.append(op.data.indptr) odeconfig.e_ops_isherm.append(op.isherm) odeconfig.e_ops_data = array(odeconfig.e_ops_data) odeconfig.e_ops_ind = array(odeconfig.e_ops_ind) odeconfig.e_ops_ptr = array(odeconfig.e_ops_ptr) odeconfig.e_ops_isherm = array(odeconfig.e_ops_isherm) #---- #take care of collapse operators, if any if any(c_ops): odeconfig.c_num = len(c_ops) for c_op in c_ops: if isinstance(c_op, list): c_op = c_op[0] n_op = c_op.dag() * c_op odeconfig.c_ops_data.append(c_op.data.data) odeconfig.c_ops_ind.append(c_op.data.indices) odeconfig.c_ops_ptr.append(c_op.data.indptr) #norm ops odeconfig.n_ops_data.append(n_op.data.data) odeconfig.n_ops_ind.append(n_op.data.indices) odeconfig.n_ops_ptr.append(n_op.data.indptr) #to array odeconfig.c_ops_data = array(odeconfig.c_ops_data) odeconfig.c_ops_ind = array(odeconfig.c_ops_ind) odeconfig.c_ops_ptr = array(odeconfig.c_ops_ptr) odeconfig.n_ops_data = array(odeconfig.n_ops_data) odeconfig.n_ops_ind = array(odeconfig.n_ops_ind) odeconfig.n_ops_ptr = array(odeconfig.n_ops_ptr) #---- #-------------------------------------------- # START CONSTANT H & C_OPS CODE #-------------------------------------------- if odeconfig.tflag == 0: if odeconfig.cflag: odeconfig.c_const_inds = arange(len(c_ops)) for c_op in c_ops: n_op = c_op.dag() * c_op H -= 0.5j * n_op #combine Hamiltonian and collapse terms into one #construct Hamiltonian data structures if options.tidy: H = H.tidyup(options.atol) odeconfig.h_data = -1.0j * H.data.data odeconfig.h_ind = H.data.indices odeconfig.h_ptr = H.data.indptr #---- #-------------------------------------------- # START STRING BASED TIME-DEPENDENCE #-------------------------------------------- elif odeconfig.tflag in array([1, 10, 11]): #take care of arguments for collapse operators, if any if any(args): for item in args.items(): odeconfig.c_args.append(item[1]) #constant Hamiltonian / string-type collapse operators if odeconfig.tflag == 1: H_inds = arange(1) H_tdterms = 0 len_h = 1 C_inds = arange(odeconfig.c_num) C_td_inds = array(c_stuff[2]) #find inds of time-dependent terms C_const_inds = setdiff1d(C_inds, C_td_inds) #find inds of constant terms C_tdterms = [c_ops[k][1] for k in C_td_inds ] #extract time-dependent coefficients (strings) odeconfig.c_const_inds = C_const_inds #store indicies of constant collapse terms odeconfig.c_td_inds = C_td_inds #store indicies of time-dependent collapse terms for k in odeconfig.c_const_inds: H -= 0.5j * (c_ops[k].dag() * c_ops[k]) if options.tidy: H = H.tidyup(options.atol) odeconfig.h_data = [H.data.data] odeconfig.h_ind = [H.data.indices] odeconfig.h_ptr = [H.data.indptr] for k in odeconfig.c_td_inds: op = c_ops[k][0].dag() * c_ops[k][0] odeconfig.h_data.append(-0.5j * op.data.data) odeconfig.h_ind.append(op.data.indices) odeconfig.h_ptr.append(op.data.indptr) odeconfig.h_data = -1.0j * array(odeconfig.h_data) odeconfig.h_ind = array(odeconfig.h_ind) odeconfig.h_ptr = array(odeconfig.h_ptr) #-------------------------------------------- # END OF IF STATEMENT #-------------------------------------------- #string-type Hamiltonian & at least one string-type collapse operator else: H_inds = arange(len(H)) H_td_inds = array(h_stuff[2]) #find inds of time-dependent terms H_const_inds = setdiff1d(H_inds, H_td_inds) #find inds of constant terms H_tdterms = [ H[k][1] for k in H_td_inds ] #extract time-dependent coefficients (strings or functions) H = array([sum(H[k] for k in H_const_inds)] + [H[k][0] for k in H_td_inds ]) #combine time-INDEPENDENT terms into one. len_h = len(H) H_inds = arange(len_h) odeconfig.h_td_inds = arange( 1, len_h) #store indicies of time-dependent Hamiltonian terms #if there are any collpase operators if odeconfig.c_num > 0: if odeconfig.tflag == 10: #constant collapse operators odeconfig.c_const_inds = arange(odeconfig.c_num) for k in odeconfig.c_const_inds: H[0] -= 0.5j * (c_ops[k].dag() * c_ops[k]) C_inds = arange(odeconfig.c_num) C_tdterms = array([]) #----- else: #some time-dependent collapse terms C_inds = arange(odeconfig.c_num) C_td_inds = array( c_stuff[2]) #find inds of time-dependent terms C_const_inds = setdiff1d( C_inds, C_td_inds) #find inds of constant terms C_tdterms = [ c_ops[k][1] for k in C_td_inds ] #extract time-dependent coefficients (strings) odeconfig.c_const_inds = C_const_inds #store indicies of constant collapse terms odeconfig.c_td_inds = C_td_inds #store indicies of time-dependent collapse terms for k in odeconfig.c_const_inds: H[0] -= 0.5j * (c_ops[k].dag() * c_ops[k]) else: #set empty objects if no collapse operators C_const_inds = arange(odeconfig.c_num) odeconfig.c_const_inds = arange(odeconfig.c_num) odeconfig.c_td_inds = array([]) C_tdterms = array([]) C_inds = array([]) #tidyup if options.tidy: H = array([H[k].tidyup(options.atol) for k in range(len_h)]) #construct data sets odeconfig.h_data = [H[k].data.data for k in range(len_h)] odeconfig.h_ind = [H[k].data.indices for k in range(len_h)] odeconfig.h_ptr = [H[k].data.indptr for k in range(len_h)] for k in odeconfig.c_td_inds: odeconfig.h_data.append(-0.5j * odeconfig.n_ops_data[k]) odeconfig.h_ind.append(odeconfig.n_ops_ind[k]) odeconfig.h_ptr.append(odeconfig.n_ops_ptr[k]) odeconfig.h_data = -1.0j * array(odeconfig.h_data) odeconfig.h_ind = array(odeconfig.h_ind) odeconfig.h_ptr = array(odeconfig.h_ptr) #-------------------------------------------- # END OF ELSE STATEMENT #-------------------------------------------- #set execuatble code for collapse expectation values and spmv col_spmv_code = "state=odeconfig.colspmv(j,ODE.t,odeconfig.c_ops_data[j],odeconfig.c_ops_ind[j],odeconfig.c_ops_ptr[j],ODE.y" col_expect_code = "n_dp+=[odeconfig.colexpect(i,ODE.t,odeconfig.n_ops_data[i],odeconfig.n_ops_ind[i],odeconfig.n_ops_ptr[i],ODE.y" for kk in range(len(odeconfig.c_args)): col_spmv_code += ",odeconfig.c_args[" + str(kk) + "]" col_expect_code += ",odeconfig.c_args[" + str(kk) + "]" col_spmv_code += ")" col_expect_code += ") for i in odeconfig.c_td_inds]" odeconfig.col_spmv_code = compile(col_spmv_code, '<string>', 'exec') odeconfig.col_expect_code = compile(col_expect_code, '<string>', 'exec') #---- #setup ode args string odeconfig.string = "" data_range = range(len(odeconfig.h_data)) for k in data_range: odeconfig.string += "odeconfig.h_data[" + str( k) + "],odeconfig.h_ind[" + str( k) + "],odeconfig.h_ptr[" + str(k) + "]" if k != data_range[-1]: odeconfig.string += "," #attach args to ode args string if len(odeconfig.c_args) > 0: for kk in range(len(odeconfig.c_args)): odeconfig.string += "," + "odeconfig.c_args[" + str(kk) + "]" #---- name = "rhs" + str(odeconfig.cgen_num) odeconfig.tdname = name cgen = Codegen(H_inds, H_tdterms, odeconfig.h_td_inds, args, C_inds, C_tdterms, odeconfig.c_td_inds, type='mc') cgen.generate(name + ".pyx") #---- #-------------------------------------------- # END OF STRING TYPE TIME DEPENDENT CODE #-------------------------------------------- #-------------------------------------------- # START PYTHON FUNCTION BASED TIME-DEPENDENCE #-------------------------------------------- elif odeconfig.tflag in array([2, 20, 22]): #take care of Hamiltonian if odeconfig.tflag == 2: # constant Hamiltonian, at least one function based collapse operators H_inds = array([0]) H_tdterms = 0 len_h = 1 else: # function based Hamiltonian H_inds = arange(len(H)) H_td_inds = array(h_stuff[1]) #find inds of time-dependent terms H_const_inds = setdiff1d(H_inds, H_td_inds) #find inds of constant terms odeconfig.h_funcs = array([H[k][1] for k in H_td_inds]) odeconfig.h_func_args = args Htd = array([H[k][0] for k in H_td_inds]) odeconfig.h_td_inds = arange(len(Htd)) H = sum(H[k] for k in H_const_inds) #take care of collapse operators C_inds = arange(odeconfig.c_num) C_td_inds = array(c_stuff[1]) #find inds of time-dependent terms C_const_inds = setdiff1d(C_inds, C_td_inds) #find inds of constant terms odeconfig.c_const_inds = C_const_inds #store indicies of constant collapse terms odeconfig.c_td_inds = C_td_inds #store indicies of time-dependent collapse terms odeconfig.c_funcs = zeros(odeconfig.c_num, dtype=FunctionType) for k in odeconfig.c_td_inds: odeconfig.c_funcs[k] = c_ops[k][1] odeconfig.c_func_args = args #combine constant collapse terms with constant H and construct data for k in odeconfig.c_const_inds: H -= 0.5j * (c_ops[k].dag() * c_ops[k]) if options.tidy: H = H.tidyup(options.atol) Htd = array( [Htd[j].tidyup(options.atol) for j in odeconfig.h_td_inds]) #setup cosntant H terms data odeconfig.h_data = -1.0j * H.data.data odeconfig.h_ind = H.data.indices odeconfig.h_ptr = H.data.indptr #setup td H terms data odeconfig.h_td_data = array( [-1.0j * Htd[k].data.data for k in odeconfig.h_td_inds]) odeconfig.h_td_ind = array( [Htd[k].data.indices for k in odeconfig.h_td_inds]) odeconfig.h_td_ptr = array( [Htd[k].data.indptr for k in odeconfig.h_td_inds]) #-------------------------------------------- # END PYTHON FUNCTION BASED TIME-DEPENDENCE #-------------------------------------------- #-------------------------------------------- # START PYTHON FUNCTION BASED HAMILTONIAN #-------------------------------------------- elif odeconfig.tflag == 3: #take care of Hamiltonian odeconfig.h_funcs = H odeconfig.h_func_args = args #take care of collapse operators odeconfig.c_const_inds = arange(odeconfig.c_num) odeconfig.c_td_inds = array([]) #find inds of time-dependent terms if len(odeconfig.c_const_inds) > 0: H = 0 for k in odeconfig.c_const_inds: H -= 0.5j * (c_ops[k].dag() * c_ops[k]) if options.tidy: H = H.tidyup(options.atol) odeconfig.h_data = -1.0j * H.data.data odeconfig.h_ind = H.data.indices odeconfig.h_ptr = H.data.indptr
def wfsolve_list_td(H_func, psi0, tlist, expt_ops, H_args, opt): """! Evolve the wave function using an ODE solver with time-dependent Hamiltonian. """ if not isket(psi0): raise TypeError("psi0 must be a ket") # # configure time-dependent terms and setup ODE solver # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if (not isinstance(H_func[0], (list, ndarray))) or (len(H_func[0]) <= 1): raise TypeError( 'Time-dependent Hamiltonians must be a list with two or more terms' ) if (not isinstance(H_func[1], (list, ndarray))) or (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError( 'Time-dependent coefficients must be list with length N-1 where N is the number of Hamiltonian terms.' ) tflag = 1 if opt.rhs_reuse == True and odeconfig.tdfunc == None: print("No previous time-dependent RHS found.") print("Generating one for you...") rhs_generate(H_func, H_args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] #create data arrays for time-dependent RHS function Hdata = [-1.0j * H_func[0][k].data.data for k in range(lenh)] Hinds = [H_func[0][k].data.indices for k in range(lenh)] Hptrs = [H_func[0][k].data.indptr for k in range(lenh)] #setup ode args string string = "" for k in range(lenh): string += "Hdata[" + str(k) + "],Hinds[" + str(k) + "],Hptrs[" + str( k) + "]," if H_args: td_consts = H_args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") #run code generator if not opt.rhs_reuse: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args) cgen.generate(odeconfig.tdname + ".pyx") os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs': [numpy.get_include()]}) code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = psi0.full() r = scipy.integrate.ode(odeconfig.tdfunc) 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]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return generic_ode_solve(r, psi0, tlist, expt_ops, opt, lambda x: x)
def mesolve_list_str_td(H_list, rho0, tlist, c_list, expt_ops, args, opt): """ Internal function for solving the master equation. See mesolve for usage. """ # # check initial state: must be a density matrix # if isket(rho0): rho0 = rho0 * rho0.dag() # # construct liouvillian # n_op = len(c_list) Lconst = 0 Ldata = [] Linds = [] Lptrs = [] Lcoeff = [] # loop over all hamiltonian terms, convert to superoperator form and # add the data of sparse matrix represenation to for h_spec in H_list: if isinstance(h_spec, Qobj): h = h_spec Lconst += -1j * (spre(h) - spost(h)) # apply tidyup ? elif isinstance(h_spec, list): h = h_spec[0] h_coeff = h_spec[1] L = -1j * (spre(h) - spost(h)) # apply tidyup ? Ldata.append(L.data.data) Linds.append(L.data.indices) Lptrs.append(L.data.indptr) Lcoeff.append(h_coeff) else: raise TypeError( "Incorrect specification of time-dependent Hamiltonian (expected string format)" ) # loop over all collapse operators for c_spec in c_list: if isinstance(c_spec, Qobj): c = c_spec cdc = c.dag() * c Lconst += spre(c) * spost(c.dag()) - 0.5 * spre(cdc) - 0.5 * spost( cdc) # apply tidyup? elif isinstance(c_spec, list): c = c_spec[0] c_coeff = c_spec[1] cdc = c.dag() * c L = spre(c) * spost(c.dag()) - 0.5 * spre(cdc) - 0.5 * spost( cdc) # apply tidyup? Ldata.append(L.data.data) Linds.append(L.data.indices) Lptrs.append(L.data.indptr) Lcoeff.append("(" + c_coeff + ")**2") else: raise TypeError( "Incorrect specification of time-dependent collapse operators (expected string format)" ) # add the constant part of the lagrangian if Lconst != 0: Ldata.append(Lconst.data.data) Linds.append(Lconst.data.indices) Lptrs.append(Lconst.data.indptr) Lcoeff.append("1.0") # the total number of liouvillian terms (hamiltonian terms + collapse operators) n_L_terms = len(Ldata) # # setup ode args string: we expand the list Ldata, Linds and Lptrs into # and explicit list of parameters # string_list = [] for k in range(n_L_terms): string_list.append("Ldata[" + str(k) + "],Linds[" + str(k) + "],Lptrs[" + str(k) + "]") for name, value in args.items(): string_list.append(str(value)) parameter_string = ",".join(string_list) # # generate and compile new cython code if necessary # if not opt.rhs_reuse or odeconfig.tdfunc == None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args) cgen.generate(odeconfig.tdname + ".pyx") os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs': [numpy.get_include()]}) code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(odeconfig.tdfunc) 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]) code = compile('r.set_f_params(' + parameter_string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return generic_ode_solve(r, rho0, tlist, expt_ops, opt, vec2mat)
def rhs_generate(H, psi0, tlist, c_ops, e_ops, ntraj=500, args={}, options=Odeoptions(), solver='me', name=None): """ Used to generate the Cython functions for solving the dynamics of a given system before using the parfor function. Parameters ---------- H : qobj System Hamiltonian. psi0 : qobj Initial state vector tlist : array_like Times at which results are recorded. ntraj : int Number of trajectories to run. c_ops : array_like ``list`` or ``array`` of collapse operators. e_ops : array_like ``list`` or ``array`` of operators for calculating expectation values. args : dict Arguments for time-dependent Hamiltonian and collapse operator terms. options : Odeoptions Instance of ODE solver options. solver: str String indicating which solver "me" or "mc" name: str Name of generated RHS """ _reset_odeconfig() #clear odeconfig #------------------------ # GENERATE MCSOLVER DATA #------------------------ if solver == 'mc': odeconfig.tlist = tlist if isinstance(ntraj, (list, ndarray)): odeconfig.ntraj = sort(ntraj)[-1] else: odeconfig.ntraj = ntraj #check for type of time-dependence (if any) time_type, h_stuff, c_stuff = _ode_checks(H, c_ops, 'mc') h_terms = len(h_stuff[0]) + len(h_stuff[1]) + len(h_stuff[2]) c_terms = len(c_stuff[0]) + len(c_stuff[1]) + len(c_stuff[2]) #set time_type for use in multiprocessing odeconfig.tflag = time_type #check for collapse operators if c_terms > 0: odeconfig.cflag = 1 else: odeconfig.cflag = 0 #Configure data _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options) os.environ['CFLAGS'] = '-w' import pyximport pyximport.install(setup_args={'include_dirs': [numpy.get_include()]}) if odeconfig.tflag in array([1, 11]): code = compile( 'from ' + odeconfig.tdname + ' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>', 'exec') exec(code) odeconfig.tdfunc = cyq_td_ode_rhs odeconfig.colspmv = col_spmv odeconfig.colexpect = col_expect else: code = compile( 'from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code) odeconfig.tdfunc = cyq_td_ode_rhs try: os.remove(odeconfig.tdname + ".pyx") except: print("Error removing pyx file. File not found.") #------------------------ # GENERATE MESOLVER STUFF #------------------------ elif solver == 'me': odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args) cgen.generate(odeconfig.tdname + ".pyx") os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs': [numpy.get_include()]}) code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code) odeconfig.tdfunc = cyq_td_ode_rhs