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 _pseudo_inverse_sparse(L, rhoss, w=None, **pseudo_args): """ Internal function for computing the pseudo inverse of an Liouvillian using sparse matrix methods. See pseudo_inverse for details. """ N = np.prod(L.dims[0][0]) rhoss_vec = operator_to_vector(rhoss) tr_op = tensor([identity(n) for n in L.dims[0][0]]) tr_op_vec = operator_to_vector(tr_op) P = zcsr_kron(rhoss_vec.data, tr_op_vec.data.T) I = sp.eye(N * N, N * N, format='csr') Q = I - P if w is None: L = 1.0j * (1e-15) * spre(tr_op) + L else: if w != 0.0: L = 1.0j * w * spre(tr_op) + L else: L = 1.0j * (1e-15) * spre(tr_op) + L if pseudo_args['use_rcm']: perm = reverse_cuthill_mckee(L.data) A = sp_permute(L.data, perm, perm) Q = sp_permute(Q, perm, perm) else: if not settings.has_mkl: A = L.data.tocsc() A.sort_indices() if pseudo_args['method'] == 'splu': if settings.has_mkl: A = L.data.tocsr() A.sort_indices() LIQ = mkl_spsolve(A, Q.toarray()) else: lu = sp.linalg.splu(A, permc_spec=pseudo_args['permc_spec'], diag_pivot_thresh=pseudo_args['diag_pivot_thresh'], options=dict(ILU_MILU=pseudo_args['ILU_MILU'])) LIQ = lu.solve(Q.toarray()) elif pseudo_args['method'] == 'spilu': lu = sp.linalg.spilu(A, permc_spec=pseudo_args['permc_spec'], fill_factor=pseudo_args['fill_factor'], drop_tol=pseudo_args['drop_tol']) LIQ = lu.solve(Q.toarray()) else: raise ValueError("unsupported method '%s'" % method) R = sp.csr_matrix(Q * LIQ) if pseudo_args['use_rcm']: rev_perm = np.argsort(perm) R = sp_permute(R, rev_perm, rev_perm, 'csr') return Qobj(R, dims=L.dims)
def _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar): """ Internal function for solving ME. Solve an ODE which solver parameters already setup (r). Calculate the required expectation values or invoke callback function at each time step. """ # # prepare output array # n_tsteps = len(tlist) e_sops_data = [] output = Result() output.solver = "mesolve" output.times = tlist if opt.store_states: output.states = [] if isinstance(e_ops, types.FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(e_ops, list): n_expt_op = len(e_ops) expt_callback = False if n_expt_op == 0: # fall back on storing states output.states = [] opt.store_states = True else: output.expect = [] output.num_expect = n_expt_op for op in e_ops: e_sops_data.append(spre(op).data) if op.isherm and rho0.isherm: output.expect.append(np.zeros(n_tsteps)) else: output.expect.append(np.zeros(n_tsteps, dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # start evolution # progress_bar.start(n_tsteps) rho = Qobj(rho0) dt = np.diff(tlist) for t_idx, t in enumerate(tlist): progress_bar.update(t_idx) if not r.successful(): raise Exception("ODE integration error: Try to increase " "the allowed number of substeps by increasing " "the nsteps parameter in the Options class.") if opt.store_states or expt_callback: rho.data = dense2D_to_fastcsr_fmode(vec2mat(r.y), rho.shape[0], rho.shape[1]) if opt.store_states: output.states.append(Qobj(rho, isherm=True)) if expt_callback: # use callback method e_ops(t, rho) for m in range(n_expt_op): if output.expect[m].dtype == complex: output.expect[m][t_idx] = expect_rho_vec(e_sops_data[m], r.y, 0) else: output.expect[m][t_idx] = expect_rho_vec(e_sops_data[m], r.y, 1) if t_idx < n_tsteps - 1: r.integrate(r.t + dt[t_idx]) progress_bar.finished() if (not opt.rhs_reuse) and (config.tdname is not None): _cython_build_cleanup(config.tdname) if opt.store_final_state: rho.data = dense2D_to_fastcsr_fmode(vec2mat(r.y), rho.shape[0], rho.shape[1]) output.final_state = Qobj(rho, dims=rho0.dims, isherm=True) return output
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)