def _mesolve_const(H, rho0, tlist, c_op_list, e_ops, args, opt, progress_bar): """ Evolve the density matrix using an ODE solver, for constant hamiltonian and collapse operators. """ 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 and isoper(H): return _sesolve_const(H, 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 opt.tidy: H = H.tidyup(opt.atol) L = liouvillian(H, c_op_list) # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel('F') if issuper(rho0): r = scipy.integrate.ode(_ode_super_func) r.set_f_params(L.data) else: if opt.use_openmp and L.data.nnz >= qset.openmp_thresh: r = scipy.integrate.ode(cy_ode_rhs_openmp) r.set_f_params(L.data.data, L.data.indices, L.data.indptr, opt.openmp_threads) else: r = scipy.integrate.ode(cy_ode_rhs) r.set_f_params(L.data.data, L.data.indices, L.data.indptr) # r = scipy.integrate.ode(_ode_rho_test) # r.set_f_params(L.data) 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]) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
def _pseudo_inverse_dense(L, rhoss, w=None, **pseudo_args): """ Internal function for computing the pseudo inverse of an Liouvillian using dense matrix methods. See pseudo_inverse for details. """ rho_vec = np.transpose(mat2vec(rhoss.full())) tr_mat = tensor([identity(n) for n in L.dims[0][0]]) tr_vec = np.transpose(mat2vec(tr_mat.full())) N = np.prod(L.dims[0][0]) I = np.identity(N * N) P = np.kron(np.transpose(rho_vec), tr_vec) Q = I - P if w is None: L = L else: L = 1.0j * w * spre(tr_mat) + L # It's possible that there's an error here! if pseudo_args['method'] == 'direct': try: LIQ = np.linalg.solve(L.full(), Q) except: LIQ = np.linalg.lstsq(L.full(), Q)[0] R = np.dot(Q, LIQ) return Qobj(R, dims=L.dims) elif pseudo_args['method'] == 'numpy': return Qobj(np.dot(Q, np.dot(np.linalg.pinv(L.full()), Q)), dims=L.dims) elif pseudo_args['method'] == 'scipy': # return Qobj(la.pinv(L.full()), dims=L.dims) return Qobj(np.dot(Q, np.dot(la.pinv(L.full()), Q)), dims=L.dims) elif pseudo_args['method'] == 'scipy2': # return Qobj(la.pinv2(L.full()), dims=L.dims) return Qobj(np.dot(Q, np.dot(la.pinv2(L.full()), Q)), dims=L.dims) else: raise ValueError("Unsupported method '%s'. Use 'direct' or 'numpy'" % method)
def _mesolve_func_td(L_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): rho0 = ket2dm(rho0) # # construct liouvillian # new_args = None if len(c_op_list) > 0: L_data = liouvillian(None, c_op_list).data else: n, m = rho0.shape if issuper(rho0): L_data = sp.csr_matrix((n, m), dtype=complex) else: L_data = sp.csr_matrix((n ** 2, m ** 2), dtype=complex) if type(args) is dict: new_args = {} for key in args: if isinstance(args[key], Qobj): if isoper(args[key]): new_args[key] = ( -1j * (spre(args[key]) - spost(args[key]))) else: new_args[key] = args[key] else: new_args[key] = args[key] elif type(args) is list or type(args) is tuple: new_args = [] for arg in args: if isinstance(arg, Qobj): if isoper(arg): new_args.append((-1j * (spre(arg) - spost(arg))).data) else: new_args.append(arg.data) else: new_args.append(arg) if type(args) is tuple: new_args = tuple(new_args) else: if isinstance(args, Qobj): if isoper(args): new_args = (-1j * (spre(args) - spost(args))) else: new_args = args else: new_args = args # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel('F') if issuper(rho0): if not opt.rhs_with_state: r = scipy.integrate.ode(_ode_super_func_td) else: r = scipy.integrate.ode(_ode_super_func_td_with_state) else: if not opt.rhs_with_state: r = scipy.integrate.ode(cy_ode_rho_func_td) else: r = scipy.integrate.ode(_ode_rho_func_td_with_state) 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]) r.set_f_params(L_data, L_func, new_args) # # 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 # L = -1.0j * (spre(H) - spost(H)) 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 _mesolve_list_func_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 # if isket(rho0): rho0 = rho0 * rho0.dag() # # construct liouvillian in list-function format # L_list = [] if opt.rhs_with_state: constant_func = lambda x, y, z: 1.0 else: constant_func = lambda x, y: 1.0 # add all hamitonian terms to the lagrangian list for h_spec in H_list: if isinstance(h_spec, Qobj): h = h_spec h_coeff = constant_func elif isinstance(h_spec, list) and isinstance(h_spec[0], Qobj): h = h_spec[0] h_coeff = h_spec[1] else: raise TypeError("Incorrect specification of time-dependent " + "Hamiltonian (expected callback function)") if isoper(h): L_list.append([(-1j * (spre(h) - spost(h))).data, h_coeff, False]) elif issuper(h): L_list.append([h.data, h_coeff, False]) else: raise TypeError("Incorrect specification of time-dependent " + "Hamiltonian (expected operator or superoperator)") # add all collapse operators to the liouvillian list for c_spec in c_list: if isinstance(c_spec, Qobj): c = c_spec c_coeff = constant_func c_square = False elif isinstance(c_spec, list) and isinstance(c_spec[0], Qobj): c = c_spec[0] c_coeff = c_spec[1] c_square = True else: raise TypeError("Incorrect specification of time-dependent " + "collapse operators (expected callback function)") if isoper(c): L_list.append([liouvillian(None, [c], data_only=True), c_coeff, c_square]) elif issuper(c): L_list.append([c.data, c_coeff, c_square]) else: raise TypeError("Incorrect specification of time-dependent " + "collapse operators (expected operator or " + "superoperator)") # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel('F') if issuper(rho0): if opt.rhs_with_state: r = scipy.integrate.ode(dsuper_list_td_with_state) else: r = scipy.integrate.ode(dsuper_list_td) else: if opt.rhs_with_state: r = scipy.integrate.ode(drho_list_td_with_state) else: r = scipy.integrate.ode(drho_list_td) 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]) r.set_f_params(L_list, 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)