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 cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cy_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, norm, dims=psi0.dims)
def rhs_generate(H, c_ops, args={}, options=Options(), name=None, cleanup=True): """ 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 : Options Instance of ODE solver options. name: str Name of generated RHS cleanup: bool Whether the generated cython file should be automatically removed or not. Notes ----- Using this function with any solver other than the mesolve function will result in an error. """ config.reset() config.options = options if name: config.tdname = name else: config.tdname = "rhs" + str(os.getpid()) + str(config.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 msg = "Incorrect specification of time-dependence: " for h_spec in H: if isinstance(h_spec, Qobj): h = h_spec if not isinstance(h, Qobj): raise TypeError(msg + "expected Qobj") if h.isoper: Lconst += -1j * (spre(h) - spost(h)) elif h.issuper: Lconst += h else: raise TypeError(msg + "expected operator or superoperator") elif isinstance(h_spec, list): h = h_spec[0] h_coeff = h_spec[1] if not isinstance(h, Qobj): raise TypeError(msg + "expected Qobj") if h.isoper: L = -1j * (spre(h) - spost(h)) elif h.issuper: L = h else: raise TypeError(msg + "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(msg + "expected string format") # loop over all collapse operators for c_spec in c_ops: if isinstance(c_spec, Qobj): c = c_spec if not isinstance(c, Qobj): raise TypeError(msg + "expected Qobj") if c.isoper: cdc = c.dag() * c Lconst += spre(c) * spost(c.dag()) - 0.5 * spre(cdc) \ - 0.5 * spost(cdc) elif c.issuper: Lconst += c else: raise TypeError(msg + "expected operator or superoperator") elif isinstance(c_spec, list): c = c_spec[0] c_coeff = c_spec[1] if not isinstance(c, Qobj): raise TypeError(msg + "expected Qobj") if c.isoper: cdc = c.dag() * c L = spre(c) * spost(c.dag()) - 0.5 * spre(cdc) \ - 0.5 * spost(cdc) c_coeff = "(" + c_coeff + ")**2" elif c.issuper: L = c else: raise TypeError(msg + "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(msg + "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, config=config) cgen.generate(config.tdname + ".pyx") code = compile('from ' + config.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) config.tdfunc = cy_td_ode_rhs if cleanup: try: os.remove(config.tdname + ".pyx") except: pass
def _sesolve_list_str_td(H_list, psi0, tlist, 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 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[%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 cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cy_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(' + parameter_string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, psi0, tlist, e_ops, opt, progress_bar, norm, dims=psi0.dims)
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(): if isinstance(value, np.ndarray): string_list.append(name) else: string_list.append(str(value)) parameter_string = ",".join(string_list) # # generate and compile new cython code if necessary # if not opt.rhs_reuse or config.tdfunc is None: if opt.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, config=config) cgen.generate(config.tdname + ".pyx") code = compile("from " + config.tdname + " import cy_td_ode_rhs", "<string>", "exec") exec(code, globals()) config.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(config.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, locals(), args) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
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, progress_bar) # 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 config.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(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[%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 config.tdfunc is None: if opt.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, config=config) cgen.generate(config.tdname + ".pyx") code = compile("from " + config.tdname + " import cy_td_ode_rhs", "<string>", "exec") exec(code, globals()) config.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(config.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 _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options, config): """Creates the appropriate data structures for the monte carlo solver based on the given time-dependent, or indepdendent, format. """ if debug: print(inspect.stack()[0][3]) config.soft_reset() # take care of expectation values, if any if any(e_ops): config.e_num = len(e_ops) for op in e_ops: if isinstance(op, list): op = op[0] config.e_ops_data.append(op.data.data) config.e_ops_ind.append(op.data.indices) config.e_ops_ptr.append(op.data.indptr) config.e_ops_isherm.append(op.isherm) config.e_ops_data = np.array(config.e_ops_data) config.e_ops_ind = np.array(config.e_ops_ind) config.e_ops_ptr = np.array(config.e_ops_ptr) config.e_ops_isherm = np.array(config.e_ops_isherm) # take care of collapse operators, if any if any(c_ops): config.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 config.c_ops_data.append(c_op.data.data) config.c_ops_ind.append(c_op.data.indices) config.c_ops_ptr.append(c_op.data.indptr) # norm ops config.n_ops_data.append(n_op.data.data) config.n_ops_ind.append(n_op.data.indices) config.n_ops_ptr.append(n_op.data.indptr) # to array config.c_ops_data = np.array(config.c_ops_data) config.c_ops_ind = np.array(config.c_ops_ind) config.c_ops_ptr = np.array(config.c_ops_ptr) config.n_ops_data = np.array(config.n_ops_data) config.n_ops_ind = np.array(config.n_ops_ind) config.n_ops_ptr = np.array(config.n_ops_ptr) if config.tflag == 0: # CONSTANT H & C_OPS CODE # ----------------------- if config.cflag: config.c_const_inds = np.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) config.h_data = -1.0j * H.data.data config.h_ind = H.data.indices config.h_ptr = H.data.indptr elif config.tflag in [1, 10, 11]: # STRING BASED TIME-DEPENDENCE # ---------------------------- # take care of arguments for collapse operators, if any if any(args): for item in args.items(): config.c_args.append(item[1]) # constant Hamiltonian / string-type collapse operators if config.tflag == 1: H_inds = np.arange(1) H_tdterms = 0 len_h = 1 C_inds = np.arange(config.c_num) # find inds of time-dependent terms C_td_inds = np.array(c_stuff[2]) # find inds of constant terms C_const_inds = np.setdiff1d(C_inds, C_td_inds) # extract time-dependent coefficients (strings) C_tdterms = [c_ops[k][1] for k in C_td_inds] # store indicies of constant collapse terms config.c_const_inds = C_const_inds # store indicies of time-dependent collapse terms config.c_td_inds = C_td_inds for k in config.c_const_inds: H -= 0.5j * (c_ops[k].dag() * c_ops[k]) if options.tidy: H = H.tidyup(options.atol) config.h_data = [H.data.data] config.h_ind = [H.data.indices] config.h_ptr = [H.data.indptr] for k in config.c_td_inds: op = c_ops[k][0].dag() * c_ops[k][0] config.h_data.append(-0.5j * op.data.data) config.h_ind.append(op.data.indices) config.h_ptr.append(op.data.indptr) config.h_data = -1.0j * np.array(config.h_data) config.h_ind = np.array(config.h_ind) config.h_ptr = np.array(config.h_ptr) else: # string-type Hamiltonian & at least one string-type # collapse operator # ----------------- H_inds = np.arange(len(H)) # find inds of time-dependent terms H_td_inds = np.array(h_stuff[2]) # find inds of constant terms H_const_inds = np.setdiff1d(H_inds, H_td_inds) # extract time-dependent coefficients (strings or functions) H_tdterms = [H[k][1] for k in H_td_inds] # combine time-INDEPENDENT terms into one. H = np.array([np.sum(H[k] for k in H_const_inds)] + [H[k][0] for k in H_td_inds], dtype=object) len_h = len(H) H_inds = np.arange(len_h) # store indicies of time-dependent Hamiltonian terms config.h_td_inds = np.arange(1, len_h) # if there are any collapse operators if config.c_num > 0: if config.tflag == 10: # constant collapse operators config.c_const_inds = np.arange(config.c_num) for k in config.c_const_inds: H[0] -= 0.5j * (c_ops[k].dag() * c_ops[k]) C_inds = np.arange(config.c_num) C_tdterms = np.array([]) else: # some time-dependent collapse terms C_inds = np.arange(config.c_num) # find inds of time-dependent terms C_td_inds = np.array(c_stuff[2]) # find inds of constant terms C_const_inds = np.setdiff1d(C_inds, C_td_inds) C_tdterms = [c_ops[k][1] for k in C_td_inds] # extract time-dependent coefficients (strings) # store indicies of constant collapse terms config.c_const_inds = C_const_inds # store indicies of time-dependent collapse terms config.c_td_inds = C_td_inds for k in config.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 = np.arange(config.c_num) config.c_const_inds = np.arange(config.c_num) config.c_td_inds = np.array([]) C_tdterms = np.array([]) C_inds = np.array([]) # tidyup if options.tidy: H = np.array([H[k].tidyup(options.atol) for k in range(len_h)], dtype=object) # construct data sets config.h_data = [H[k].data.data for k in range(len_h)] config.h_ind = [H[k].data.indices for k in range(len_h)] config.h_ptr = [H[k].data.indptr for k in range(len_h)] for k in config.c_td_inds: config.h_data.append(-0.5j * config.n_ops_data[k]) config.h_ind.append(config.n_ops_ind[k]) config.h_ptr.append(config.n_ops_ptr[k]) config.h_data = -1.0j * np.array(config.h_data) config.h_ind = np.array(config.h_ind) config.h_ptr = np.array(config.h_ptr) # set execuatble code for collapse expectation values and spmv col_spmv_code = ("state = _cy_col_spmv_func(j, ODE.t, " + "config.c_ops_data[j], config.c_ops_ind[j], " + "config.c_ops_ptr[j], ODE.y") col_expect_code = ("for i in config.c_td_inds: " + "n_dp.append(_cy_col_expect_func(i, ODE.t, " + "config.n_ops_data[i], " + "config.n_ops_ind[i], " + "config.n_ops_ptr[i], ODE.y") for kk in range(len(config.c_args)): col_spmv_code += ",config.c_args[" + str(kk) + "]" col_expect_code += ",config.c_args[" + str(kk) + "]" col_spmv_code += ")" col_expect_code += "))" config.col_spmv_code = col_spmv_code config.col_expect_code = col_expect_code # setup ode args string config.string = "" data_range = range(len(config.h_data)) for k in data_range: config.string += ("config.h_data[" + str(k) + "], config.h_ind[" + str(k) + "], config.h_ptr[" + str(k) + "]") if k != data_range[-1]: config.string += "," # attach args to ode args string if len(config.c_args) > 0: for kk in range(len(config.c_args)): config.string += "," + "config.c_args[" + str(kk) + "]" name = "rhs" + str(os.getpid()) + str(config.cgen_num) config.tdname = name cgen = Codegen(H_inds, H_tdterms, config.h_td_inds, args, C_inds, C_tdterms, config.c_td_inds, type='mc', config=config) cgen.generate(name + ".pyx") elif config.tflag in [2, 20, 22]: # PYTHON LIST-FUNCTION BASED TIME-DEPENDENCE # ------------------------------------------ # take care of Hamiltonian if config.tflag == 2: # constant Hamiltonian, at least one function based collapse # operators H_inds = np.array([0]) H_tdterms = 0 len_h = 1 else: # function based Hamiltonian H_inds = np.arange(len(H)) H_td_inds = np.array(h_stuff[1]) H_const_inds = np.setdiff1d(H_inds, H_td_inds) config.h_funcs = np.array([H[k][1] for k in H_td_inds]) config.h_func_args = args Htd = np.array([H[k][0] for k in H_td_inds], dtype=object) config.h_td_inds = np.arange(len(Htd)) H = np.sum(H[k] for k in H_const_inds) # take care of collapse operators C_inds = np.arange(config.c_num) # find inds of time-dependent terms C_td_inds = np.array(c_stuff[1]) # find inds of constant terms C_const_inds = np.setdiff1d(C_inds, C_td_inds) # store indicies of constant collapse terms config.c_const_inds = C_const_inds # store indicies of time-dependent collapse terms config.c_td_inds = C_td_inds config.c_funcs = np.zeros(config.c_num, dtype=FunctionType) for k in config.c_td_inds: config.c_funcs[k] = c_ops[k][1] config.c_func_args = args # combine constant collapse terms with constant H and construct data for k in config.c_const_inds: H -= 0.5j * (c_ops[k].dag() * c_ops[k]) if options.tidy: H = H.tidyup(options.atol) Htd = np.array([Htd[j].tidyup(options.atol) for j in config.h_td_inds], dtype=object) # setup constant H terms data config.h_data = -1.0j * H.data.data config.h_ind = H.data.indices config.h_ptr = H.data.indptr # setup td H terms data config.h_td_data = np.array( [-1.0j * Htd[k].data.data for k in config.h_td_inds]) config.h_td_ind = np.array( [Htd[k].data.indices for k in config.h_td_inds]) config.h_td_ptr = np.array( [Htd[k].data.indptr for k in config.h_td_inds]) elif config.tflag == 3: # PYTHON FUNCTION BASED HAMILTONIAN # --------------------------------- # take care of Hamiltonian config.h_funcs = H config.h_func_args = args # take care of collapse operators config.c_const_inds = np.arange(config.c_num) config.c_td_inds = np.array([]) if len(config.c_const_inds) > 0: H = 0 for k in config.c_const_inds: H -= 0.5j * (c_ops[k].dag() * c_ops[k]) if options.tidy: H = H.tidyup(options.atol) config.h_data = -1.0j * H.data.data config.h_ind = H.data.indices config.h_ptr = H.data.indptr
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, progress_bar) # 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 config.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(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[%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 config.tdfunc is None: if opt.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, config=config) cgen.generate(config.tdname + ".pyx") code = compile('from ' + config.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) config.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(config.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 _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 = [] Lobj = [] # 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) if isinstance(h_coeff, Cubic_Spline): Lobj.append(h_coeff.coeffs) 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) # Check which components should use OPENMP omp_components = None if qset.has_openmp: if opt.use_openmp: omp_components = openmp_components(Lptrs) # # 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)) # Add object terms to end of ode args string for k in range(len(Lobj)): string_list.append("Lobj[%d]" % k) for name, value in args.items(): if isinstance(value, np.ndarray): string_list.append(name) else: string_list.append(str(value)) parameter_string = ",".join(string_list) # # generate and compile new cython code if necessary # if not opt.rhs_reuse or config.tdfunc is None: if opt.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, config=config, use_openmp=opt.use_openmp, omp_components=omp_components, omp_threads=opt.openmp_threads) cgen.generate(config.tdname + ".pyx") code = compile('from ' + config.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) config.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel('F') if issuper(rho0): r = scipy.integrate.ode(_td_ode_rhs_super) code = compile('r.set_f_params([' + parameter_string + '])', '<string>', 'exec') else: r = scipy.integrate.ode(config.tdfunc) code = compile('r.set_f_params(' + parameter_string + ')', '<string>', 'exec') 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]) exec(code, locals(), args) # # 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, e_ops, args, opt, progress_bar): """ Internal function for solving the master equation. See mesolve for usage. """ if debug: print(inspect.stack()[0][3]) if psi0.isket: oper_evo = False elif psi0.isunitary: oper_evo = True else: raise TypeError("The unitary solver requires psi0 to be" " a ket as initial state" " or a unitary as initial operator.") # # construct dynamics generator # Ldata = [] Linds = [] Lptrs = [] Lcoeff = [] Lobj = [] # 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) if isinstance(h_coeff, Cubic_Spline): Lobj.append(h_coeff.coeffs) Lcoeff.append(h_coeff) # the total number of Hamiltonian terms n_L_terms = len(Ldata) # Check which components should use OPENMP omp_components = None if qset.has_openmp: if opt.use_openmp: omp_components = openmp_components(Lptrs) # # 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)) # Add object terms to end of ode args string for k in range(len(Lobj)): string_list.append("Lobj[%d]" % k) for name, value in args.items(): if isinstance(value, np.ndarray): string_list.append(name) else: string_list.append(str(value)) parameter_string = ",".join(string_list) # # generate and compile new cython code if necessary # if not opt.rhs_reuse or config.tdfunc is None: if opt.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, config=config, use_openmp=opt.use_openmp, omp_components=omp_components, omp_threads=opt.openmp_threads) cgen.generate(config.tdname + ".pyx") code = compile('from ' + config.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) config.tdfunc = cy_td_ode_rhs # # setup integrator # if oper_evo: initial_vector = psi0.full().ravel('F') r = scipy.integrate.ode(_td_ode_rhs_oper) code = compile('r.set_f_params([' + parameter_string + '])', '<string>', 'exec') else: initial_vector = psi0.full().ravel() r = scipy.integrate.ode(config.tdfunc) code = compile('r.set_f_params(' + parameter_string + ')', '<string>', 'exec') 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]) exec(code, locals(), args) # Remove RHS cython file if necessary if not opt.rhs_reuse and config.tdname: _cython_build_cleanup(config.tdname) # # call generic ODE code # return _generic_ode_solve(r, psi0, tlist, e_ops, opt, progress_bar, dims=psi0.dims)
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 = [] Lobj = [] me_cops_coeff = [] me_cops_obj = [] me_cops_obj_flags = [] # loop over all hamiltonian terms, convert to superoperator form and # add the data of sparse matrix representation to n_not_const_terms = 0 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): n_not_const_terms +=1 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) if isinstance(h_coeff, Cubic_Spline): Lobj.append(h_coeff.coeffs) 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): n_not_const_terms +=1 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) if isinstance(c_coeff, Cubic_Spline): me_cops_obj.append(c_coeff.coeffs) me_cops_obj_flags.append(n_not_const_terms) me_cops_coeff.append(c_coeff) else: c_coeff = "(" + c_coeff + ")**2" Lcoeff.append(c_coeff) elif issuper(c): L = c if isinstance(c_coeff, Cubic_Spline): me_cops_obj.append(c_coeff.coeffs) me_cops_obj_flags.append(-n_not_const_terms) me_cops_coeff.append(c_coeff) else: Lcoeff.append(c_coeff) 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)") #prepend the constant part of the liouvillian if Lconst != 0: Ldata = [Lconst.data.data]+Ldata Linds = [Lconst.data.indices]+Linds Lptrs = [Lconst.data.indptr]+Lptrs Lcoeff = ["1.0"]+Lcoeff else: me_cops_obj_flags = [kk-1 for kk in me_cops_obj_flags] # the total number of liouvillian terms (hamiltonian terms + # collapse operators) n_L_terms = len(Ldata) n_td_cops = len(me_cops_obj) # Check which components should use OPENMP omp_components = None if qset.has_openmp: if opt.use_openmp: omp_components = openmp_components(Lptrs) # # 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)) # Add H object terms to ode args string for k in range(len(Lobj)): string_list.append("Lobj[%d]" % k) # Add cop object terms to end of ode args string for k in range(len(me_cops_obj)): string_list.append("me_cops_obj[%d]" % k) for name, value in args.items(): if isinstance(value, np.ndarray): string_list.append(name) else: string_list.append(str(value)) parameter_string = ",".join(string_list) # # generate and compile new cython code if necessary # if not opt.rhs_reuse or config.tdfunc is None: if opt.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename cgen = Codegen(h_terms=len(Lcoeff), h_tdterms=Lcoeff, c_td_splines=me_cops_coeff, c_td_spline_flags=me_cops_obj_flags, args=args, config=config, use_openmp=opt.use_openmp, omp_components=omp_components, omp_threads=opt.openmp_threads) cgen.generate(config.tdname + ".pyx") code = compile('from ' + config.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) config.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel('F') if issuper(rho0): r = scipy.integrate.ode(_td_ode_rhs_super) code = compile('r.set_f_params([' + parameter_string + '])', '<string>', 'exec') else: r = scipy.integrate.ode(config.tdfunc) code = compile('r.set_f_params(' + parameter_string + ')', '<string>', 'exec') 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]) exec(code, locals(), args) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
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 cy_td_ode_rhs", "<string>", "exec") exec(code, globals()) odeconfig.tdfunc = cy_td_ode_rhs try: os.remove(odeconfig.tdname + ".pyx") except: pass
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: for name, value in args.items(): if isinstance(value, np.ndarray): globals()['var_%s'%name] = value string += 'var_%s,'%name else: string += str(value) + ',' # 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 cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cy_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)