def _correlation_me_4op_2t(H, rho0, tlist, taulist, c_ops, a_op, b_op, c_op, d_op, reverse=False, args=None, options=Odeoptions()): """ Calculate the four-operator two-time correlation function on the form <A(t)B(t+tau)C(t+tau)D(t)>. See, Gardiner, Quantum Noise, Section 5.2.1 """ if debug: print(inspect.stack()[0][3]) if rho0 is None: rho0 = steadystate(H, c_ops) elif rho0 and isket(rho0): rho0 = ket2dm(rho0) C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex) rho_t = mesolve( H, rho0, tlist, c_ops, [], args=args, options=options).states for t_idx, rho in enumerate(rho_t): C_mat[t_idx, :] = mesolve(H, d_op * rho * a_op, taulist, c_ops, [b_op * c_op], args=args, options=options).expect[0] return C_mat
def _correlation_me_2op_2t(H, rho0, tlist, taulist, c_ops, a_op, b_op, reverse=False, args=None, options=Odeoptions()): """ Internal function for calculating correlation functions using the master equation solver. See :func:`correlation` for usage. """ if debug: print(inspect.stack()[0][3]) if rho0 is None: rho0 = steadystate(H, c_ops) elif rho0 and isket(rho0): rho0 = ket2dm(rho0) C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex) rho_t_list = mesolve( H, rho0, tlist, c_ops, [], args=args, options=options).states if reverse: # <A(t)B(t+tau)> for t_idx, rho_t in enumerate(rho_t_list): C_mat[t_idx, :] = mesolve(H, rho_t * a_op, taulist, c_ops, [b_op], args=args, options=options).expect[0] else: # <A(t+tau)B(t)> for t_idx, rho_t in enumerate(rho_t_list): C_mat[t_idx, :] = mesolve(H, b_op * rho_t, taulist, c_ops, [a_op], args=args, options=options).expect[0] return C_mat
def _correlation_me_2t(H, state0, tlist, taulist, c_ops, a_op, b_op, c_op, args=None, options=Options()): """ Internal function for calculating the three-operator two-time correlation function: <A(t)B(t+tau)C(t)> using a master equation solver. """ # the solvers only work for positive time differences and the correlators # require positive tau if state0 is None: rho0 = steadystate(H, c_ops) tlist = [0] elif isket(state0): rho0 = ket2dm(state0) else: rho0 = state0 if debug: print(inspect.stack()[0][3]) rho_t = mesolve(H, rho0, tlist, c_ops, [], args=args, options=options).states corr_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex) H_shifted, _args = _transform_H_t_shift(H, args) for t_idx, rho in enumerate(rho_t): if not isinstance(H, Qobj): _args["_t0"] = tlist[t_idx] corr_mat[t_idx, :] = mesolve(H_shifted, c_op * rho * a_op, taulist, c_ops, [b_op], args=_args, options=options).expect[0] if t_idx == 1: options.rhs_reuse = True return corr_mat
def _correlation_me_2op_2t(H, rho0, tlist, taulist, c_ops, a_op, b_op, reverse=False, args=None, options=Odeoptions()): """ Internal function for calculating correlation functions using the master equation solver. See :func:`correlation` for usage. """ if debug: print(inspect.stack()[0][3]) if rho0 is None: rho0 = steadystate(H, c_ops) elif rho0 and isket(rho0): rho0 = ket2dm(rho0) C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex) rho_t_list = mesolve(H, rho0, tlist, c_ops, [], args=args, options=options).states if reverse: # <A(t)B(t+tau)> for t_idx, rho_t in enumerate(rho_t_list): C_mat[t_idx, :] = mesolve(H, rho_t * a_op, taulist, c_ops, [b_op], args=args, options=options).expect[0] else: # <A(t+tau)B(t)> for t_idx, rho_t in enumerate(rho_t_list): C_mat[t_idx, :] = mesolve(H, b_op * rho_t, taulist, c_ops, [a_op], args=args, options=options).expect[0] return C_mat
def _parallel_mesolve(n, N, H, tlist, c_op_list, args, options): col_idx, row_idx = np.unravel_index(n, (N, N)) rho0 = Qobj(sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(N, N), dtype=complex)) output = mesolve(H, rho0, tlist, c_op_list, [], args, options, _safe_mode=False) return output
def _correlation_me_4op_1t(H, rho0, tlist, c_ops, a_op, b_op, c_op, d_op, args=None, options=Odeoptions()): """ Calculate the four-operator two-time correlation function on the form <A(0)B(tau)C(tau)D(0)>. See, Gardiner, Quantum Noise, Section 5.2.1 """ if debug: print(inspect.stack()[0][3]) if rho0 is None: rho0 = steadystate(H, c_ops) elif rho0 and isket(rho0): rho0 = ket2dm(rho0) return mesolve(H, d_op * rho0 * a_op, tlist, c_ops, [b_op * c_op], args=args, options=options).expect[0]
def _parallel_mesolve(n, N, H, tlist, c_op_list, args, options): col_idx, row_idx = np.unravel_index(n, (N, N)) rho0 = Qobj(sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(N,N), dtype=complex)) output = mesolve(H, rho0, tlist, c_op_list, [], args, options, _safe_mode=False) return output
def _correlation_me_2t(H, state0, tlist, taulist, c_ops, a_op, b_op, c_op, args={}, options=Options()): """ Internal function for calculating the three-operator two-time correlation function: <A(t)B(t+tau)C(t)> using a master equation solver. """ # the solvers only work for positive time differences and the correlators # require positive tau if state0 is None: rho0 = steadystate(H, c_ops) tlist = [0] elif isket(state0): rho0 = ket2dm(state0) else: rho0 = state0 if debug: print(inspect.stack()[0][3]) rho_t = mesolve(H, rho0, tlist, c_ops, [], args=args, options=options).states corr_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex) H_shifted, c_ops_shifted, _args = _transform_L_t_shift(H, c_ops, args) if config.tdname: _cython_build_cleanup(config.tdname) rhs_clear() for t_idx, rho in enumerate(rho_t): if not isinstance(H, Qobj): _args["_t0"] = tlist[t_idx] corr_mat[t_idx, :] = mesolve( H_shifted, c_op * rho * a_op, taulist, c_ops_shifted, [b_op], args=_args, options=options ).expect[0] if t_idx == 1: options.rhs_reuse = True if config.tdname: _cython_build_cleanup(config.tdname) rhs_clear() return corr_mat
def correlation_ode(H, rho0, tlist, taulist, c_op_list, a_op, b_op): """ Internal function for calculating correlation functions using the master equation solver. See :func:`correlation` usage. """ if rho0 == None: rho0 = steadystate(H, co_op_list) C_mat = np.zeros([np.size(tlist),np.size(taulist)],dtype=complex) rho_t = mesolve(H, rho0, tlist, c_op_list, []).states for t_idx in range(len(tlist)): C_mat[t_idx,:] = mesolve(H, b_op * rho_t[t_idx], taulist, c_op_list, [a_op]).expect[0] return C_mat
def coherence_function_g2(H, rho0, taulist, c_ops, a_op, solver="me", args=None, options=Odeoptions()): """ Calculate the second-order quantum coherence function: .. math:: g^{(2)}(\\tau) = \\frac{\\langle a^\\dagger(0)a^\\dagger(\\tau)a(\\tau)a(0)\\rangle} {\\langle a^\\dagger(\\tau)a(\\tau)\\rangle \\langle a^\\dagger(0)a(0)\\rangle} Parameters ---------- H : :class:`qutip.qobj.Qobj` system Hamiltonian. rho0 : :class:`qutip.qobj.Qobj` Initial state density matrix (or state vector). If 'rho0' is 'None', then the steady state will be used as initial state. taulist : *list* / *array* list of times for :math:`\\tau`. c_ops : list of :class:`qutip.qobj.Qobj` list of collapse operators. a_op : :class:`qutip.qobj.Qobj` The annihilation operator of the mode. solver : str choice of solver (currently only 'me') Returns ------- g2, G2: tuble of *array* The normalized and unnormalized second-order coherence function. """ # first calculate the photon number if rho0 is None: rho0 = steadystate(H, c_ops) n = np.array([expect(rho0, a_op.dag() * a_op)]) else: n = mesolve( H, rho0, taulist, c_ops, [a_op.dag() * a_op], args=args, options=options).expect[0] # calculate the correlation function G2 and normalize with n to obtain g2 G2 = correlation_4op_1t(H, rho0, taulist, c_ops, a_op.dag(), a_op.dag(), a_op, a_op, solver=solver, args=args, options=options) g2 = G2 / (n[0] * n) return g2, G2
def correlation_ode(H, rho0, tlist, taulist, c_op_list, a_op, b_op): """ Internal function for calculating correlation functions using the master equation solver. See :func:`correlation` usage. """ if rho0 == None: rho0 = steadystate(H, co_op_list) C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex) rho_t = mesolve(H, rho0, tlist, c_op_list, []).states for t_idx in range(len(tlist)): C_mat[t_idx, :] = mesolve(H, b_op * rho_t[t_idx], taulist, c_op_list, [a_op]).expect[0] return C_mat
def solve_system_unpack_qutip(pack): """ These functions are used for the parallel computing, where we need to call the function with just one variable. Here we extract the index of the process and unpack the parameters given to solve the system. By default, the value for hbar is 1, and the absolute and relative errors are 10^{-8} and 10^{-6} respectively. :param pack: (list) List with the following parameters: [index of the parallel computation, time, density0, parameters, hamiltonian]. To pass the values of default parameters, all of them must be in the sixth element of the list as a dictionary, e.g {'hbar': 1, 'atol': 1e-8}. :return: (list) list with the index of the computation al the solution of the system. """ i, H, psi0, times = pack[:4] if len(pack) > 4: extra_params = pack[-1] else: extra_params = {} if 'args' not in extra_params: extra_params['args'] = {} if 'options' not in extra_params: extra_params['options'] = Options() if 'dim' not in extra_params: extra_params['dim'] = 3 if 'only_final' not in extra_params: extra_params['only_final'] = False if 'c_ops' not in extra_params: extra_params['c_ops'] = None result = mesolve(H, psi0, times, args=extra_params['args'], options=extra_params['options'], c_ops=extra_params['c_ops']) if extra_params['only_final']: states = np.zeros([extra_params['dim']], dtype=complex) if extra_params['c_ops'] is None: states[:] = result.states[-1].full()[:, 0] else: prob = np.diag(result.states[-1].full()) phases = np.exp(1j * np.angle(result.states[-1].full())[0, :]) states[:] = np.sqrt(prob) * phases else: states = np.zeros([extra_params['dim'], len(times)], dtype=complex) for j in range(0, len(times)): if extra_params['c_ops'] is None: states[:, j] = result.states[j].full()[:, 0] else: prob = np.diag(result.states[j].full()) phases = np.exp(1j * np.angle(result.states[j].full())[0, :]) states[:, j] = np.sqrt(prob) * phases return [i, states]
def correlation_ss_ode(H, tlist, c_op_list, a_op, b_op, rho0=None): """ Internal function for calculating correlation functions using the master equation solver. See :func:`correlation_ss` usage. """ L = liouvillian(H, c_op_list) if rho0 is None: rho0 = steady(L) return mesolve(H, b_op * rho0, tlist, c_op_list, [a_op]).expect[0]
def correlation_ss_ode(H, tlist, c_op_list, a_op, b_op, rho0=None): """ Internal function for calculating correlation functions using the master equation solver. See :func:`correlation_ss` usage. """ L = liouvillian(H, c_op_list) if rho0 == None: rho0 = steady(L) return mesolve(H, b_op * rho0, tlist, c_op_list, [a_op]).expect[0]
def _correlation_me_2op_1t(H, rho0, tlist, c_ops, a_op, b_op, reverse=False, args=None, options=Options()): """ Internal function for calculating correlation functions using the master equation solver. See :func:`correlation_ss` for usage. """ if debug: print(inspect.stack()[0][3]) if rho0 is None: rho0 = steadystate(H, c_ops) elif rho0 and isket(rho0): rho0 = ket2dm(rho0) if reverse: # <A(t)B(t+tau)> return mesolve(H, rho0 * a_op, tlist, c_ops, [b_op], args=args, options=options).expect[0] else: # <A(t+tau)B(t)> return mesolve(H, b_op * rho0, tlist, c_ops, [a_op], args=args, options=options).expect[0]
def _correlation_me_4op_2t(H, rho0, tlist, taulist, c_ops, a_op, b_op, c_op, d_op, reverse=False, args=None, options=Odeoptions()): """ Calculate the four-operator two-time correlation function on the form <A(t)B(t+tau)C(t+tau)D(t)>. See, Gardiner, Quantum Noise, Section 5.2.1 """ if debug: print(inspect.stack()[0][3]) if rho0 is None: rho0 = steadystate(H, c_ops) elif rho0 and isket(rho0): rho0 = ket2dm(rho0) C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex) rho_t = mesolve(H, rho0, tlist, c_ops, [], args=args, options=options).states for t_idx, rho in enumerate(rho_t): C_mat[t_idx, :] = mesolve(H, d_op * rho * a_op, taulist, c_ops, [b_op * c_op], args=args, options=options).expect[0] return C_mat
def _parallel_mesolve(n, N, H, tlist, c_op_list, args, options, dims=None): col_idx, row_idx = np.unravel_index(n, (N, N)) rho0 = projection(N, row_idx, col_idx) rho0.dims = dims output = mesolve(H, rho0, tlist, c_ops=c_op_list, args=args, options=options, _safe_mode=False) return output
def testExpectSolverCompatibility(self): """ expect: operator list and state list """ c_ops = [0.0001 * sigmaz()] e_ops = [sigmax(), sigmay(), sigmaz(), sigmam(), sigmap()] times = np.linspace(0, 10, 100) res1 = mesolve(sigmax(), fock(2, 0), times, c_ops, e_ops) res2 = mesolve(sigmax(), fock(2, 0), times, c_ops, []) e1 = res1.expect e2 = expect(e_ops, res2.states) assert_(len(e1) == len(e2)) for n in range(len(e1)): assert_(len(e1[n]) == len(e2[n])) assert_(isinstance(e1[n], np.ndarray)) assert_(isinstance(e2[n], np.ndarray)) assert_(e1[n].dtype == e2[n].dtype) assert_(all(abs(e1[n] - e2[n]) < 1e-12))
def floquet_modes_table(f_modes_0, f_energies, tlist, H, T, args=None): """ Pre-calculate the Floquet modes for a range of times spanning the floquet period. Can later be used as a table to look up the floquet modes for any time. Parameters ---------- f_modes_0 : list of :class:`qutip.qobj` (kets) Floquet modes at :math:`t` f_energies : list Floquet energies. tlist : array The list of times at which to evaluate the floquet modes. H : :class:`qutip.qobj` system Hamiltonian, time-dependent with period `T` T : float The period of the time-dependence of the hamiltonian. args : dictionary dictionary with variables required to evaluate H Returns ------- output : nested list A nested list of Floquet modes as kets for each time in `tlist` """ # truncate tlist to the driving period tlist_period = tlist[np.where(tlist <= T)] f_modes_table_t = [[] for t in tlist_period] opt = Options() opt.rhs_reuse = True for n, f_mode in enumerate(f_modes_0): output = mesolve(H, f_mode, tlist_period, [], [], args, opt) for t_idx, f_state_t in enumerate(output.states): f_modes_table_t[t_idx].append( f_state_t * exp(1j * f_energies[n] * tlist_period[t_idx])) return f_modes_table_t
def _correlation_me_2op_1t(H, rho0, tlist, c_ops, a_op, b_op, reverse=False, args=None, options=Odeoptions()): """ Internal function for calculating correlation functions using the master equation solver. See :func:`correlation_ss` for usage. """ if debug: print(inspect.stack()[0][3]) if rho0 is None: rho0 = steadystate(H, c_ops) elif rho0 and isket(rho0): rho0 = ket2dm(rho0) if reverse: # <A(t)B(t+tau)> return mesolve(H, rho0 * a_op, tlist, c_ops, [b_op], args=args, options=options).expect[0] else: # <A(t+tau)B(t)> return mesolve(H, b_op * rho0, tlist, c_ops, [a_op], args=args, options=options).expect[0]
def _correlation_me_gtt(H, rho0, tlist, taulist, c_ops, a_op, b_op, c_op, d_op): """ Calculate the correlation function <A(t)B(t+tau)C(t+tau)D(t)> (gtt = general two-time) See, Gardiner, Quantum Noise, Section 5.2.1 .. note:: Experimental. """ if rho0 is None: rho0 = steadystate(H, c_ops) C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex) rho_t = mesolve(H, rho0, tlist, c_op_list, []).states for t_idx, rho in enumerate(rho_t): C_mat[t_idx, :] = mesolve(H, d_op * rho * a_op, taulist, c_ops, [b_op * c_op]).expect[0] return C_mat
def _correlation_me_ss_gtt(H, tlist, c_ops, a_op, b_op, c_op, d_op, rho0=None): """ Calculate the correlation function <A(0)B(tau)C(tau)D(0)> (ss_gtt = steadystate general two-time) See, Gardiner, Quantum Noise, Section 5.2.1 .. note:: Experimental. """ if rho0 is None: rho0 = steadystate(H, c_ops) return mesolve(H, d_op * rho0 * a_op, tlist, c_ops, [b_op * c_op]).expect[0]
def _correlation_me_4op_1t(H, rho0, tlist, c_ops, a_op, b_op, c_op, d_op, args=None, options=Options()): """ Calculate the four-operator two-time correlation function on the form <A(0)B(tau)C(tau)D(0)>. See, Gardiner, Quantum Noise, Section 5.2.1 """ if debug: print(inspect.stack()[0][3]) if rho0 is None: rho0 = steadystate(H, c_ops) elif rho0 and isket(rho0): rho0 = ket2dm(rho0) return mesolve(H, d_op * rho0 * a_op, tlist, c_ops, [b_op * c_op], args=args, options=options).expect[0]
def propagator(H, t, c_op_list=[], args={}, options=None, unitary_mode='batch', parallel=False, progress_bar=None, _safe_mode=True, **kwargs): r""" Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\rho_{\mathrm vec}(t) = U(t) \rho_{\mathrm vec}(0)` where :math:`\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. unitary_mode = str ('batch', 'single') Solve all basis vectors simulaneously ('batch') or individually ('single'). parallel : bool {False, True} Run the propagator in parallel mode. This will override the unitary_mode settings if set to True. progress_bar: BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. By default no progress bar is used, and if set to True a TextProgressBar will be used. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ kw = _default_kwargs() if 'num_cpus' in kwargs: num_cpus = kwargs['num_cpus'] else: num_cpus = kw['num_cpus'] if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t if _safe_mode: _solver_safety_check(H, None, c_ops=c_op_list, e_ops=[], args=args) td_type = _td_format_check(H, c_op_list, solver='me') if isinstance( H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) if unitary_mode == 'batch': # batch don't work with function Hamiltonian unitary_mode = 'single' elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims if parallel: unitary_mode = 'single' u = np.zeros([N, N, len(tlist)], dtype=complex) output = parallel_map(_parallel_sesolve, range(N), task_args=(N, H, tlist, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N): for k, t in enumerate(tlist): u[:, n, k] = output[n].states[k].full().T else: if unitary_mode == 'single': output = sesolve(H, qeye(dims[0]), tlist, [], args, options, _safe_mode=False) if len(tlist) == 2: return output.states[-1] else: return output.states elif unitary_mode == 'batch': u = np.zeros(len(tlist), dtype=object) _rows = np.array([(N + 1) * m for m in range(N)]) _cols = np.zeros_like(_rows) _data = np.ones_like(_rows, dtype=complex) psi0 = Qobj(sp.coo_matrix((_data, (_rows, _cols))).tocsr()) if td_type[1] > 0 or td_type[2] > 0: H2 = [] for k in range(len(H)): if isinstance(H[k], list): H2.append([tensor(qeye(N), H[k][0]), H[k][1]]) else: H2.append(tensor(qeye(N), H[k])) else: H2 = tensor(qeye(N), H) options.normalize_output = False output = sesolve(H2, psi0, tlist, [], args=args, options=options, _safe_mode=False) for k, t in enumerate(tlist): u[k] = sp_reshape(output.states[k].data, (N, N)) unit_row_norm(u[k].data, u[k].indptr, u[k].shape[0]) u[k] = u[k].T.tocsr() else: raise Exception('Invalid unitary mode.') elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) unitary_mode = 'single' N = H0.shape[0] sqrt_N = int(np.sqrt(N)) dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve, range(N * N), task_args=(sqrt_N, H, tlist, c_op_list, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: rho0 = qeye(N, N) rho0.dims = [[sqrt_N, sqrt_N], [sqrt_N, sqrt_N]] output = mesolve(H, psi0, tlist, [], args, options, _safe_mode=False) if len(tlist) == 2: return output.states[-1] else: return output.states else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) unitary_mode = 'single' N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve, range(N * N), task_args=(N, H, tlist, c_op_list, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n, (N, N)) rho0 = Qobj( sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(N, N), dtype=complex)) output = mesolve(H, rho0, tlist, c_op_list, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() if len(tlist) == 2: if unitary_mode == 'batch': return Qobj(u[-1], dims=dims) else: return Qobj(u[:, :, 1], dims=dims) else: if unitary_mode == 'batch': return np.array([Qobj(u[k], dims=dims) for k in range(len(tlist))], dtype=object) else: return np.array( [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))], dtype=object)
def propagator(H, t, c_op_list=[], args={}, options=None, parallel=False, progress_bar=None, **kwargs): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. parallel : bool {False, True} Run the propagator in parallel mode. progress_bar: BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. By default no progress bar is used, and if set to True a TextProgressBar will be used. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ kw = _default_kwargs() if 'num_cpus' in kwargs: num_cpus = kwargs['num_cpus'] else: num_cpus = kw['num_cpus'] if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t td_type = _td_format_check(H, c_op_list, solver='me')[2] if td_type > 0: rhs_generate(H, c_op_list, args=args, options=options) if isinstance( H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_sesolve, range(N), task_args=(N, H, tlist, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N): for k, t in enumerate(tlist): u[:, n, k] = output[n].states[k].full().T else: progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T progress_bar.finished() # todo: evolving a batch of wave functions: # psi_0_list = [basis(N, n) for n in range(N)] # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options) # for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] sqrt_N = int(np.sqrt(N)) dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve, range(N * N), task_args=(sqrt_N, H, tlist, c_op_list, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N) for n in range(0, N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n, (sqrt_N, sqrt_N)) rho0 = Qobj( sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(sqrt_N, sqrt_N), dtype=complex)) output = mesolve(H, rho0, tlist, [], [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve, range(N * N), task_args=(N, H, tlist, c_op_list, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n, (N, N)) rho0 = Qobj( sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(N, N), dtype=complex)) output = mesolve(H, rho0, tlist, c_op_list, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return np.array( [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))], dtype=object)
def propagator(H, t, c_op_list, args=None, options=None): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Odeoptions` with options for the ODE solver. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ if options is None: options = Odeoptions() options.rhs_reuse = True rhs_clear() elif options.rhs_reuse: msg = ("propagator is using previously defined rhs " + "function (options.rhs_reuse = True)") warnings.warn(msg) tlist = [0, t] if isinstance(t, (int, float, np.int64, np.float64)) else t if len(c_op_list) == 0: # calculate propagator for the wave function if isinstance(H, types.FunctionType): H0 = H(0.0, args) N = H0.shape[0] dims = H0.dims elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] N = H0.shape[0] dims = H0.dims else: N = H.shape[0] dims = H.dims u = np.zeros([N, N, len(tlist)], dtype=complex) for n in range(0, N): psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T # todo: evolving a batch of wave functions: # psi_0_list = [basis(N, n) for n in range(N)] # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options) # for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) if isinstance(H, types.FunctionType): H0 = H(0.0, args) N = H0.shape[0] dims = [H0.dims, H0.dims] elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] N = H0.shape[0] dims = [H0.dims, H0.dims] else: N = H.shape[0] dims = [H.dims, H.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) for n in range(0, N * N): psi0 = basis(N * N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
def propagator(H, t, c_op_list, H_args=None, opt=None): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. H_args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ if opt is None: opt = Odeoptions() opt.rhs_reuse = True tlist = [0, t] if isinstance(t, (int, float, np.int64, np.float64)) else t if len(c_op_list) == 0: # calculate propagator for the wave function if isinstance(H, types.FunctionType): H0 = H(0.0, H_args) N = H0.shape[0] dims = H0.dims elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] N = H0.shape[0] dims = H0.dims else: N = H.shape[0] dims = H.dims u = np.zeros([N, N, len(tlist)], dtype=complex) for n in range(0, N): psi0 = basis(N, n) output = mesolve(H, psi0, tlist, [], [], H_args, opt) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T # todo: evolving a batch of wave functions: #psi_0_list = [basis(N, n) for n in range(N)] #psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], H_args, opt) #for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) if isinstance(H, types.FunctionType): H0 = H(0.0, H_args) N = H0.shape[0] dims = [H0.dims, H0.dims] elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] N = H0.shape[0] dims = [H0.dims, H0.dims] else: N = H.shape[0] dims = [H.dims, H.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) for n in range(0, N * N): psi0 = basis(N * N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, c_op_list, [], H_args, opt) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
def run_state(self, init_state=None, analytical=False, states=None, noisy=True, **kwargs): """ If `analytical` is False, use :func:`qutip.mesolve` to calculate the time of the state evolution and return the result. Other arguments of mesolve can be given as keyword arguments. If `analytical` is True, calculate the propagator with matrix exponentiation and return a list of matrices. Noise will be neglected in this choice. Parameters ---------- init_state: Qobj Initial density matrix or state vector (ket). analytical: bool If True, calculate the evolution with matrices exponentiation. states: :class:`qutip.Qobj`, optional Old API, same as init_state. **kwargs Keyword arguments for the qutip solver. Returns ------- evo_result: :class:`qutip.Result` If ``analytical`` is False, an instance of the class :class:`qutip.Result` will be returned. If ``analytical`` is True, a list of matrices representation is returned. """ if states is not None: warnings.warn( "states will be deprecated and replaced by init_state", DeprecationWarning) if init_state is None and states is None: raise ValueError("Qubit state not defined.") elif init_state is None: # just to keep the old parameters `states`, # it is replaced by init_state init_state = states if analytical: if kwargs or self.noise: raise warnings.warn("Analytical matrices exponentiation" "does not process noise or" "any keyword arguments.") return self.run_analytically(init_state=init_state) # kwargs can not contain H or tlist if "H" in kwargs or "tlist" in kwargs: raise ValueError( "`H` and `tlist` are already specified by the processor " "and can not be given as a keyword argument") # construct qobjevo for unitary evolution if "args" in kwargs: noisy_qobjevo, sys_c_ops = self.get_qobjevo(args=kwargs["args"], noisy=noisy) else: noisy_qobjevo, sys_c_ops = self.get_qobjevo(noisy=noisy) # add collpase operators into kwargs if "c_ops" in kwargs: if isinstance(kwargs["c_ops"], (Qobj, QobjEvo)): kwargs["c_ops"] += [kwargs["c_ops"]] + sys_c_ops else: kwargs["c_ops"] += sys_c_ops else: kwargs["c_ops"] = sys_c_ops evo_result = mesolve(H=noisy_qobjevo, rho0=init_state, tlist=noisy_qobjevo.tlist, **kwargs) return evo_result
def propagator(H, t, c_op_list=[], args={}, options=None, unitary_mode='batch', parallel=False, progress_bar=None, **kwargs): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. unitary_mode = str ('batch', 'single') Solve all basis vectors simulaneously ('batch') or individually ('single'). parallel : bool {False, True} Run the propagator in parallel mode. This will override the unitary_mode settings if set to True. progress_bar: BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. By default no progress bar is used, and if set to True a TextProgressBar will be used. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ kw = _default_kwargs() if 'num_cpus' in kwargs: num_cpus = kwargs['num_cpus'] else: num_cpus = kw['num_cpus'] if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t td_type = _td_format_check(H, c_op_list, solver='me') if isinstance(H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims if parallel: unitary_mode = 'single' u = np.zeros([N, N, len(tlist)], dtype=complex) output = parallel_map(_parallel_sesolve,range(N), task_args=(N,H, tlist,args,options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N): for k, t in enumerate(tlist): u[:, n, k] = output[n].states[k].full().T else: if unitary_mode == 'single': u = np.zeros([N, N, len(tlist)], dtype=complex) progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T progress_bar.finished() elif unitary_mode =='batch': u = np.zeros(len(tlist), dtype=object) _rows = np.array([(N+1)*m for m in range(N)]) _cols = np.zeros_like(_rows) _data = np.ones_like(_rows,dtype=complex) psi0 = Qobj(sp.coo_matrix((_data,(_rows,_cols))).tocsr()) if td_type[1] > 0 or td_type[2] > 0: H2 = [] for k in range(len(H)): if isinstance(H[k], list): H2.append([tensor(qeye(N), H[k][0]), H[k][1]]) else: H2.append(tensor(qeye(N), H[k])) else: H2 = tensor(qeye(N), H) output = sesolve(H2, psi0, tlist, [] , args = args, _safe_mode=False, options=Options(normalize_output=False)) for k, t in enumerate(tlist): u[k] = sp_reshape(output.states[k].data, (N, N)) unit_row_norm(u[k].data, u[k].indptr, u[k].shape[0]) u[k] = u[k].T.tocsr() else: raise Exception('Invalid unitary mode.') elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) unitary_mode = 'single' N = H0.shape[0] sqrt_N = int(np.sqrt(N)) dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve,range(N * N), task_args=(sqrt_N,H,tlist,c_op_list,args,options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N) for n in range(0, N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n,(sqrt_N,sqrt_N)) rho0 = Qobj(sp.csr_matrix(([1],([row_idx],[col_idx])), shape=(sqrt_N,sqrt_N), dtype=complex)) output = mesolve(H, rho0, tlist, [], [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) unitary_mode = 'single' N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve,range(N * N), task_args=(N,H,tlist,c_op_list,args,options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n,(N,N)) rho0 = Qobj(sp.csr_matrix(([1],([row_idx],[col_idx])), shape=(N,N), dtype=complex)) output = mesolve(H, rho0, tlist, c_op_list, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() if len(tlist) == 2: if unitary_mode == 'batch': return Qobj(u[-1], dims=dims) else: return Qobj(u[:, :, 1], dims=dims) else: if unitary_mode == 'batch': return np.array([Qobj(u[k], dims=dims) for k in range(len(tlist))], dtype=object) else: return np.array([Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))], dtype=object)
def coherence_function_g2(H, state0, taulist, c_ops, a_op, solver="me", args={}, options=Options(ntraj=[20, 100])): """ Calculate the normalized second-order quantum coherence function: .. math:: g^{(2)}(\\tau) = \\frac{\\langle A^\\dagger(0)A^\\dagger(\\tau)A(\\tau)A(0)\\rangle} {\\langle A^\\dagger(\\tau)A(\\tau)\\rangle \\langle A^\\dagger(0)A(0)\\rangle} using the quantum regression theorem and the evolution solver indicated by the `solver` parameter. Parameters ---------- H : Qobj system Hamiltonian, may be time-dependent for solver choice of `me` or `mc`. state0 : Qobj Initial state density matrix :math:`\\rho(t_0)` or state vector :math:`\\psi(t_0)`. If 'state0' is 'None', then the steady state will be used as the initial state. The 'steady-state' is only implemented for the `me` and `es` solvers. taulist : array_like list of times for :math:`\\tau`. taulist must be positive and contain the element `0`. c_ops : list list of collapse operators, may be time-dependent for solver choice of `me` or `mc`. a_op : Qobj operator A. solver : str choice of solver (`me` for master-equation and `es` for exponential series). options : Options solver options class. `ntraj` is taken as a two-element list because the `mc` correlator calls `mcsolve()` recursively; by default, `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in the `mc` correlator; by default, `mc_corr_eps=1e-10`. Returns ------- g2, G2 : tuple The normalized and unnormalized second-order coherence function. """ # first calculate the photon number if state0 is None: state0 = steadystate(H, c_ops) n = np.array([expect(state0, a_op.dag() * a_op)]) else: n = mesolve(H, state0, taulist, c_ops, [a_op.dag() * a_op]).expect[0] # calculate the correlation function G2 and normalize with n to obtain g2 G2 = correlation_3op_1t(H, state0, taulist, c_ops, a_op.dag(), a_op.dag()*a_op, a_op, solver=solver, args=args, options=options) g2 = G2 / (n[0] * n) return g2, G2
def propagator(H, t, c_op_list=[], args={}, options=None, parallel=False, progress_bar=None, **kwargs): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. parallel : bool {False, True} Run the propagator in parallel mode. progress_bar: BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. By default no progress bar is used, and if set to True a TextProgressBar will be used. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ kw = _default_kwargs() if 'num_cpus' in kwargs: num_cpus = kwargs['num_cpus'] else: num_cpus = kw['num_cpus'] if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t td_type = _td_format_check(H, c_op_list, solver='me')[2] if td_type > 0: rhs_generate(H, c_op_list, args=args, options=options) if isinstance(H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_sesolve,range(N), task_args=(N,H,tlist,args,options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N): for k, t in enumerate(tlist): u[:, n, k] = output[n].states[k].full().T else: progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T progress_bar.finished() # todo: evolving a batch of wave functions: # psi_0_list = [basis(N, n) for n in range(N)] # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options) # for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] sqrt_N = int(np.sqrt(N)) dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve,range(N * N), task_args=(sqrt_N,H,tlist,c_op_list,args,options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N) for n in range(0, N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n,(sqrt_N,sqrt_N)) rho0 = Qobj(sp.csr_matrix(([1],([row_idx],[col_idx])), shape=(sqrt_N,sqrt_N), dtype=complex)) output = mesolve(H, rho0, tlist, [], [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve,range(N * N), task_args=(N,H,tlist,c_op_list,args,options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n,(N,N)) rho0 = Qobj(sp.csr_matrix(([1],([row_idx],[col_idx])), shape=(N,N), dtype=complex)) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return np.array([Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))], dtype=object)
def propagator(H, t, c_op_list, args=None, options=None, sparse=False, progress_bar=None): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. progress_bar: BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. By default no progress bar is used, and if set to True a TextProgressBar will be used. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t if isinstance( H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T progress_bar.finished() # todo: evolving a batch of wave functions: # psi_0_list = [basis(N, n) for n in range(N)] # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options) # for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, [], [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if sparse: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) psi0 = basis(N * N, n) psi0.dims = [dims[0], 1] rho0 = vector_to_operator(psi0) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = operator_to_vector( output.states[k]).full(squeeze=True) progress_bar.finished() else: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) psi0 = basis(N * N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
def propagator(H, t, c_op_list, args=None, options=None, sparse=False): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t if isinstance(H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) for n in range(0, N): psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T # todo: evolving a batch of wave functions: # psi_0_list = [basis(N, n) for n in range(N)] # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options) # for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) for n in range(0, N): psi0 = basis(N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, [], [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if sparse: for n in range(N * N): psi0 = basis(N * N, n) psi0.dims = [dims[0], 1] rho0 = vector_to_operator(psi0) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = operator_to_vector( output.states[k]).full(squeeze=True) else: for n in range(N * N): psi0 = basis(N * N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
def coherence_function_g2(H, rho0, taulist, c_ops, a_op, solver="me", args=None, options=Odeoptions()): """ Calculate the second-order quantum coherence function: .. math:: g^{(2)}(\\tau) = \\frac{\\langle a^\\dagger(0)a^\\dagger(\\tau)a(\\tau)a(0)\\rangle} {\\langle a^\\dagger(\\tau)a(\\tau)\\rangle \\langle a^\\dagger(0)a(0)\\rangle} Parameters ---------- H : :class:`qutip.qobj.Qobj` system Hamiltonian. rho0 : :class:`qutip.qobj.Qobj` Initial state density matrix (or state vector). If 'rho0' is 'None', then the steady state will be used as initial state. taulist : *list* / *array* list of times for :math:`\\tau`. c_ops : list of :class:`qutip.qobj.Qobj` list of collapse operators. a_op : :class:`qutip.qobj.Qobj` The annihilation operator of the mode. solver : str choice of solver (currently only 'me') Returns ------- g2, G2: tuble of *array* The normalized and unnormalized second-order coherence function. """ # first calculate the photon number if rho0 is None: rho0 = steadystate(H, c_ops) n = np.array([expect(rho0, a_op.dag() * a_op)]) else: n = mesolve(H, rho0, taulist, c_ops, [a_op.dag() * a_op], args=args, options=options).expect[0] # calculate the correlation function G2 and normalize with n to obtain g2 G2 = correlation_4op_1t(H, rho0, taulist, c_ops, a_op.dag(), a_op.dag(), a_op, a_op, solver=solver, args=args, options=options) g2 = G2 / (n[0] * n) return g2, G2