def brmesolve(H, psi0, tlist, a_ops=[], e_ops=[], c_ops=[], args={}, use_secular=True, tol=qset.atol, spectra_cb=None, options=None, progress_bar=None, _safe_mode=True): """ Solves for the dynamics of a system using the Bloch-Redfield master equation, given an input Hamiltonian, Hermitian bath-coupling terms and their associated spectrum functions, as well as possible Lindblad collapse operators. For time-independent systems, the Hamiltonian must be given as a Qobj, whereas the bath-coupling terms (a_ops), must be written as a nested list of operator - spectrum function pairs, where the frequency is specified by the `w` variable. *Example* a_ops = [[a+a.dag(),lambda w: 0.2*(w>=0)]] For time-dependent systems, the Hamiltonian, a_ops, and Lindblad collapse operators (c_ops), can be specified in the QuTiP string-based time-dependent format. For the a_op spectra, the frequency variable must be `w`, and the string cannot contain any other variables other than the possibility of having a time-dependence through the time variable `t`: *Example* a_ops = [[a+a.dag(), '0.2*exp(-t)*(w>=0)']] Parameters ---------- H : Qobj / list System Hamiltonian given as a Qobj or nested list in string-based format. psi0: Qobj Initial density matrix or state vector (ket). tlist : array_like List of times for evaluating evolution a_ops : list Nested list of Hermitian system operators that couple to the bath degrees of freedom, along with their associated spectra. e_ops : list List of operators for which to evaluate expectation values. c_ops : list List of system collapse operators, or nested list in string-based format. args : dict (not implimented) Placeholder for future implementation, kept for API consistency. use_secular : bool {True} Use secular approximation when evaluating bath-coupling terms. tol : float {qutip.setttings.atol} Tolerance used for removing small values after basis transformation. spectra_cb : list DEPRECIATED. Do not use. options : :class:`qutip.solver.Options` Options for the solver. progress_bar : BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. Returns ------- result: :class:`qutip.solver.Result` An instance of the class :class:`qutip.solver.Result`, which contains either an array of expectation values, for operators given in e_ops, or a list of states for the times specified by `tlist`. """ if isinstance(c_ops, Qobj): c_ops = [c_ops] if isinstance(e_ops, Qobj): e_ops = [e_ops] if isinstance(e_ops, dict): e_ops_dict = e_ops e_ops = [e for e in e_ops.values()] else: e_ops_dict = None if not (spectra_cb is None): warnings.warn("The use of spectra_cb is depreciated.", DeprecationWarning) _a_ops = [] for kk, a in enumerate(a_ops): _a_ops.append([a, spectra_cb[kk]]) a_ops = _a_ops if _safe_mode: _solver_safety_check(H, psi0, a_ops + c_ops, e_ops, args) # check for type (if any) of time-dependent inputs _, n_func, n_str = _td_format_check(H, a_ops + c_ops) if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() if (not options.rhs_reuse) or (not config.tdfunc): # reset config collapse and time-dependence flags to default values config.reset() #check if should use OPENMP check_use_openmp(options) if n_str == 0: R, ekets = bloch_redfield_tensor(H, a_ops, spectra_cb=None, c_ops=c_ops) output = Result() output.solver = "brmesolve" output.times = tlist results = bloch_redfield_solve(R, ekets, psi0, tlist, e_ops, options, progress_bar=progress_bar) if e_ops: output.expect = results else: output.states = results return output elif n_str != 0 and n_func == 0: output = _td_brmesolve(H, psi0, tlist, a_ops=a_ops, e_ops=e_ops, c_ops=c_ops, use_secular=use_secular, tol=tol, options=options, progress_bar=progress_bar, _safe_mode=_safe_mode) return output else: raise Exception('Cannot mix func and str formats.')
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 brmesolve(H, psi0, tlist, a_ops=[], e_ops=[], c_ops=[], args={}, use_secular=True, sec_cutoff = 0.1, tol=qset.atol, spectra_cb=None, options=None, progress_bar=None, _safe_mode=True, verbose=False): """ Solves for the dynamics of a system using the Bloch-Redfield master equation, given an input Hamiltonian, Hermitian bath-coupling terms and their associated spectrum functions, as well as possible Lindblad collapse operators. For time-independent systems, the Hamiltonian must be given as a Qobj, whereas the bath-coupling terms (a_ops), must be written as a nested list of operator - spectrum function pairs, where the frequency is specified by the `w` variable. *Example* a_ops = [[a+a.dag(),lambda w: 0.2*(w>=0)]] For time-dependent systems, the Hamiltonian, a_ops, and Lindblad collapse operators (c_ops), can be specified in the QuTiP string-based time-dependent format. For the a_op spectra, the frequency variable must be `w`, and the string cannot contain any other variables other than the possibility of having a time-dependence through the time variable `t`: *Example* a_ops = [[a+a.dag(), '0.2*exp(-t)*(w>=0)']] It is also possible to use Cubic_Spline objects for time-dependence. In the case of a_ops, Cubic_Splines must be passed as a tuple: *Example* a_ops = [ [a+a.dag(), ( f(w), g(t)] ] where f(w) and g(t) are strings or Cubic_spline objects for the bath spectrum and time-dependence, respectively. Finally, if one has bath-couplimg terms of the form H = f(t)*a + conj[f(t)]*a.dag(), then the correct input format is *Example* a_ops = [ [(a,a.dag()), (f(w), g1(t), g2(t))],... ] where f(w) is the spectrum of the operators while g1(t) and g2(t) are the time-dependence of the operators `a` and `a.dag()`, respectively Parameters ---------- H : Qobj / list System Hamiltonian given as a Qobj or nested list in string-based format. psi0: Qobj Initial density matrix or state vector (ket). tlist : array_like List of times for evaluating evolution a_ops : list Nested list of Hermitian system operators that couple to the bath degrees of freedom, along with their associated spectra. e_ops : list List of operators for which to evaluate expectation values. c_ops : list List of system collapse operators, or nested list in string-based format. args : dict Placeholder for future implementation, kept for API consistency. use_secular : bool {True} Use secular approximation when evaluating bath-coupling terms. sec_cutoff : float {0.1} Cutoff for secular approximation. tol : float {qutip.setttings.atol} Tolerance used for removing small values after basis transformation. spectra_cb : list DEPRECIATED. Do not use. options : :class:`qutip.solver.Options` Options for the solver. progress_bar : BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. Returns ------- result: :class:`qutip.solver.Result` An instance of the class :class:`qutip.solver.Result`, which contains either an array of expectation values, for operators given in e_ops, or a list of states for the times specified by `tlist`. """ _prep_time = time.time() #This allows for passing a list of time-independent Qobj #as allowed by mesolve if isinstance(H, list): if np.all([isinstance(h,Qobj) for h in H]): H = sum(H) if isinstance(c_ops, Qobj): c_ops = [c_ops] if isinstance(e_ops, Qobj): e_ops = [e_ops] if isinstance(e_ops, dict): e_ops_dict = e_ops e_ops = [e for e in e_ops.values()] else: e_ops_dict = None if not (spectra_cb is None): warnings.warn("The use of spectra_cb is depreciated.", DeprecationWarning) _a_ops = [] for kk, a in enumerate(a_ops): _a_ops.append([a,spectra_cb[kk]]) a_ops = _a_ops if _safe_mode: _solver_safety_check(H, psi0, a_ops+c_ops, e_ops, args) # check for type (if any) of time-dependent inputs _, n_func, n_str = _td_format_check(H, a_ops+c_ops) if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() if (not options.rhs_reuse) or (not config.tdfunc): # reset config collapse and time-dependence flags to default values config.reset() #check if should use OPENMP check_use_openmp(options) if n_str == 0: R, ekets = bloch_redfield_tensor(H, a_ops, spectra_cb=None, c_ops=c_ops, use_secular=use_secular, sec_cutoff=sec_cutoff) output = Result() output.solver = "brmesolve" output.times = tlist results = bloch_redfield_solve(R, ekets, psi0, tlist, e_ops, options, progress_bar=progress_bar) if e_ops: output.expect = results else: output.states = results return output elif n_str != 0 and n_func == 0: output = _td_brmesolve(H, psi0, tlist, a_ops=a_ops, e_ops=e_ops, c_ops=c_ops, args=args, use_secular=use_secular, sec_cutoff=sec_cutoff, tol=tol, options=options, progress_bar=progress_bar, _safe_mode=_safe_mode, verbose=verbose, _prep_time=_prep_time) return output else: raise Exception('Cannot mix func and str formats.')
def mesolve(H, rho0, tlist, c_ops, e_ops, args={}, options=None, progress_bar=BaseProgressBar()): """ Master equation evolution of a density matrix for a given Hamiltonian. Evolve the state vector or density matrix (`rho0`) using a given Hamiltonian (`H`) and an [optional] set of collapse operators (`c_op_list`), by integrating the set of ordinary differential equations that define the system. In the absence of collapse operators the system is evolved according to the unitary evolution of the Hamiltonian. The output is either the state vector at arbitrary points in time (`tlist`), or the expectation values of the supplied operators (`e_ops`). If e_ops is a callback function, it is invoked for each time in `tlist` with time and the state as arguments, and the function does not use any return values. **Time-dependent operators** For problems with time-dependent problems `H` and `c_ops` can be callback functions that takes two arguments, time and `args`, and returns the Hamiltonian or Liouvillian for the system at that point in time (*callback format*). Alternatively, `H` and `c_ops` can be a specified in a nested-list format where each element in the list is a list of length 2, containing an operator (:class:`qutip.qobj`) at the first element and where the second element is either a string (*list string format*), a callback function (*list callback format*) that evaluates to the time-dependent coefficient for the corresponding operator, or a numpy array (*list array format*) which specifies the value of the coefficient to the corresponding operator for each value of t in tlist. *Examples* H = [[H0, 'sin(w*t)'], [H1, 'sin(2*w*t)']] H = [[H0, sin(w*tlist)], [H1, sin(2*w*tlist)]] H = [[H0, f0_t], [H1, f1_t]] where f0_t and f1_t are python functions with signature f_t(t, args). In the *list string format* and *list callback format*, the string expression and the callback function must evaluate to a real or complex number (coefficient for the corresponding operator). In all cases of time-dependent operators, `args` is a dictionary of parameters that is used when evaluating operators. It is passed to the callback functions as second argument .. note:: If an element in the list-specification of the Hamiltonian or the list of collapse operators are in super-operator for it will be added to the total Liouvillian of the problem with out further transformation. This allows for using mesolve for solving master equations that are not on standard Lindblad form. .. note:: On using callback function: mesolve transforms all :class:`qutip.qobj` objects to sparse matrices before handing the problem to the integrator function. In order for your callback function to work correctly, pass all :class:`qutip.qobj` objects that are used in constructing the Hamiltonian via args. mesolve will check for :class:`qutip.qobj` in `args` and handle the conversion to sparse matrices. All other :class:`qutip.qobj` objects that are not passed via `args` will be passed on to the integrator in scipy which will raise an NotImplemented exception. Parameters ---------- H : :class:`qutip.Qobj` system Hamiltonian, or a callback function for time-dependent Hamiltonians. rho0 : :class:`qutip.Qobj` initial density matrix or state vector (ket). tlist : *list* / *array* list of times for :math:`t`. c_ops : list of :class:`qutip.Qobj` single collapse operator, or list of collapse operators. e_ops : list of :class:`qutip.Qobj` / callback function single single operator or list of operators for which to evaluate expectation values. args : *dictionary* dictionary of parameters for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. progress_bar: TextProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. Returns ------- output: :class:`qutip.solver` An instance of the class :class:`qutip.solver`, which contains either an *array* of expectation values for the times specified by `tlist`, or an *array* or state vectors or density matrices corresponding to the times in `tlist` [if `e_ops` is an empty list], or nothing if a callback function was given in place of operators for which to calculate the expectation values. """ # check whether c_ops or e_ops is is a single operator # if so convert it to a list containing only that operator if isinstance(c_ops, Qobj): c_ops = [c_ops] if isinstance(e_ops, Qobj): e_ops = [e_ops] if isinstance(e_ops, dict): e_ops_dict = e_ops e_ops = [e for e in e_ops.values()] else: e_ops_dict = None # convert array based time-dependence to string format H, c_ops, args = _td_wrap_array_str(H, c_ops, args, tlist) # check for type (if any) of time-dependent inputs _, n_func, n_str = _td_format_check(H, c_ops) if options is None: options = Options() if (not options.rhs_reuse) or (not config.tdfunc): # reset config collapse and time-dependence flags to default values config.reset() res = None # # dispatch the appropriate solver # if ( (c_ops and len(c_ops) > 0) or (not isket(rho0)) or (isinstance(H, Qobj) and issuper(H)) or (isinstance(H, list) and isinstance(H[0], Qobj) and issuper(H[0])) ): # # we have collapse operators # # # find out if we are dealing with all-constant hamiltonian and # collapse operators or if we have at least one time-dependent # operator. Then delegate to appropriate solver... # if isinstance(H, Qobj): # constant hamiltonian if n_func == 0 and n_str == 0: # constant collapse operators res = _mesolve_const(H, rho0, tlist, c_ops, e_ops, args, options, progress_bar) elif n_str > 0: # constant hamiltonian but time-dependent collapse # operators in list string format res = _mesolve_list_str_td([H], rho0, tlist, c_ops, e_ops, args, options, progress_bar) elif n_func > 0: # constant hamiltonian but time-dependent collapse # operators in list function format res = _mesolve_list_func_td([H], rho0, tlist, c_ops, e_ops, args, options, progress_bar) elif isinstance(H, (types.FunctionType, types.BuiltinFunctionType, partial)): # function-callback style time-dependence: must have constant # collapse operators if n_str > 0: # or n_func > 0: raise TypeError( "Incorrect format: function-format " + "Hamiltonian cannot be mixed with " + "time-dependent collapse operators." ) else: res = _mesolve_func_td(H, rho0, tlist, c_ops, e_ops, args, options, progress_bar) elif isinstance(H, list): # determine if we are dealing with list of [Qobj, string] or # [Qobj, function] style time-dependencies (for pure python and # cython, respectively) if n_func > 0: res = _mesolve_list_func_td(H, rho0, tlist, c_ops, e_ops, args, options, progress_bar) else: res = _mesolve_list_str_td(H, rho0, tlist, c_ops, e_ops, args, options, progress_bar) else: raise TypeError("Incorrect specification of Hamiltonian " + "or collapse operators.") else: # # no collapse operators: unitary dynamics # if n_func > 0: res = _sesolve_list_func_td(H, rho0, tlist, e_ops, args, options, progress_bar) elif n_str > 0: res = _sesolve_list_str_td(H, rho0, tlist, e_ops, args, options, progress_bar) elif isinstance(H, (types.FunctionType, types.BuiltinFunctionType, partial)): res = _sesolve_func_td(H, rho0, tlist, e_ops, args, options, progress_bar) else: res = _sesolve_const(H, rho0, tlist, e_ops, args, options, progress_bar) if e_ops_dict: res.expect = {e: res.expect[n] for n, e in enumerate(e_ops_dict.keys())} return res
def mesolve(H, rho0, tlist, c_ops=[], e_ops=[], args={}, options=None, progress_bar=None, _safe_mode=True): """ Master equation evolution of a density matrix for a given Hamiltonian and set of collapse operators, or a Liouvillian. Evolve the state vector or density matrix (`rho0`) using a given Hamiltonian (`H`) and an [optional] set of collapse operators (`c_ops`), by integrating the set of ordinary differential equations that define the system. In the absence of collapse operators the system is evolved according to the unitary evolution of the Hamiltonian. The output is either the state vector at arbitrary points in time (`tlist`), or the expectation values of the supplied operators (`e_ops`). If e_ops is a callback function, it is invoked for each time in `tlist` with time and the state as arguments, and the function does not use any return values. If either `H` or the Qobj elements in `c_ops` are superoperators, they will be treated as direct contributions to the total system Liouvillian. This allows to solve master equations that are not on standard Lindblad form by passing a custom Liouvillian in place of either the `H` or `c_ops` elements. **Time-dependent operators** For time-dependent problems, `H` and `c_ops` can be callback functions that takes two arguments, time and `args`, and returns the Hamiltonian or Liouvillian for the system at that point in time (*callback format*). Alternatively, `H` and `c_ops` can be a specified in a nested-list format where each element in the list is a list of length 2, containing an operator (:class:`qutip.qobj`) at the first element and where the second element is either a string (*list string format*), a callback function (*list callback format*) that evaluates to the time-dependent coefficient for the corresponding operator, or a NumPy array (*list array format*) which specifies the value of the coefficient to the corresponding operator for each value of t in tlist. *Examples* H = [[H0, 'sin(w*t)'], [H1, 'sin(2*w*t)']] H = [[H0, f0_t], [H1, f1_t]] where f0_t and f1_t are python functions with signature f_t(t, args). H = [[H0, np.sin(w*tlist)], [H1, np.sin(2*w*tlist)]] In the *list string format* and *list callback format*, the string expression and the callback function must evaluate to a real or complex number (coefficient for the corresponding operator). In all cases of time-dependent operators, `args` is a dictionary of parameters that is used when evaluating operators. It is passed to the callback functions as second argument. **Additional options** Additional options to mesolve can be set via the `options` argument, which should be an instance of :class:`qutip.solver.Options`. Many ODE integration options can be set this way, and the `store_states` and `store_final_state` options can be used to store states even though expectation values are requested via the `e_ops` argument. .. note:: If an element in the list-specification of the Hamiltonian or the list of collapse operators are in superoperator form it will be added to the total Liouvillian of the problem with out further transformation. This allows for using mesolve for solving master equations that are not on standard Lindblad form. .. note:: On using callback function: mesolve transforms all :class:`qutip.qobj` objects to sparse matrices before handing the problem to the integrator function. In order for your callback function to work correctly, pass all :class:`qutip.qobj` objects that are used in constructing the Hamiltonian via args. mesolve will check for :class:`qutip.qobj` in `args` and handle the conversion to sparse matrices. All other :class:`qutip.qobj` objects that are not passed via `args` will be passed on to the integrator in scipy which will raise an NotImplemented exception. Parameters ---------- H : :class:`qutip.Qobj` System Hamiltonian, or a callback function for time-dependent Hamiltonians, or alternatively a system Liouvillian. rho0 : :class:`qutip.Qobj` initial density matrix or state vector (ket). tlist : *list* / *array* list of times for :math:`t`. c_ops : list of :class:`qutip.Qobj` single collapse operator, or list of collapse operators, or a list of Liouvillian superoperators. e_ops : list of :class:`qutip.Qobj` / callback function single single operator or list of operators for which to evaluate expectation values. args : *dictionary* dictionary of parameters for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the solver. progress_bar : BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. Returns ------- result: :class:`qutip.Result` An instance of the class :class:`qutip.Result`, which contains either an *array* `result.expect` of expectation values for the times specified by `tlist`, or an *array* `result.states` of state vectors or density matrices corresponding to the times in `tlist` [if `e_ops` is an empty list], or nothing if a callback function was given in place of operators for which to calculate the expectation values. """ # check whether c_ops or e_ops is is a single operator # if so convert it to a list containing only that operator if isinstance(c_ops, Qobj): c_ops = [c_ops] if isinstance(e_ops, Qobj): e_ops = [e_ops] if isinstance(e_ops, dict): e_ops_dict = e_ops e_ops = [e for e in e_ops.values()] else: e_ops_dict = None if _safe_mode: _solver_safety_check(H, rho0, c_ops, e_ops, args) if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() # check if rho0 is a superoperator, in which case e_ops argument should # be empty, i.e., e_ops = [] if issuper(rho0) and not e_ops == []: raise TypeError("Must have e_ops = [] when initial condition rho0 is" + " a superoperator.") # convert array based time-dependence to string format H, c_ops, args = _td_wrap_array_str(H, c_ops, args, tlist) # check for type (if any) of time-dependent inputs _, n_func, n_str = _td_format_check(H, c_ops) if options is None: options = Options() if (not options.rhs_reuse) or (not config.tdfunc): # reset config collapse and time-dependence flags to default values config.reset() #check if should use OPENMP check_use_openmp(options) res = None # # dispatch the appropriate solver # if ((c_ops and len(c_ops) > 0) or (not isket(rho0)) or (isinstance(H, Qobj) and issuper(H)) or (isinstance(H, list) and isinstance(H[0], Qobj) and issuper(H[0]))): # # we have collapse operators, or rho0 is not a ket, # or H is a Liouvillian # # # find out if we are dealing with all-constant hamiltonian and # collapse operators or if we have at least one time-dependent # operator. Then delegate to appropriate solver... # if isinstance(H, Qobj): # constant hamiltonian if n_func == 0 and n_str == 0: # constant collapse operators res = _mesolve_const(H, rho0, tlist, c_ops, e_ops, args, options, progress_bar) elif n_str > 0: # constant hamiltonian but time-dependent collapse # operators in list string format res = _mesolve_list_str_td([H], rho0, tlist, c_ops, e_ops, args, options, progress_bar) elif n_func > 0: # constant hamiltonian but time-dependent collapse # operators in list function format res = _mesolve_list_func_td([H], rho0, tlist, c_ops, e_ops, args, options, progress_bar) elif isinstance( H, (types.FunctionType, types.BuiltinFunctionType, partial)): # function-callback style time-dependence: must have constant # collapse operators if n_str > 0: # or n_func > 0: raise TypeError("Incorrect format: function-format " + "Hamiltonian cannot be mixed with " + "time-dependent collapse operators.") else: res = _mesolve_func_td(H, rho0, tlist, c_ops, e_ops, args, options, progress_bar) elif isinstance(H, list): # determine if we are dealing with list of [Qobj, string] or # [Qobj, function] style time-dependencies (for pure python and # cython, respectively) if n_func > 0: res = _mesolve_list_func_td(H, rho0, tlist, c_ops, e_ops, args, options, progress_bar) else: res = _mesolve_list_str_td(H, rho0, tlist, c_ops, e_ops, args, options, progress_bar) else: raise TypeError("Incorrect specification of Hamiltonian " + "or collapse operators.") else: # # no collapse operators: unitary dynamics # if n_func > 0: res = _sesolve_list_func_td(H, rho0, tlist, e_ops, args, options, progress_bar) elif n_str > 0: res = _sesolve_list_str_td(H, rho0, tlist, e_ops, args, options, progress_bar) elif isinstance( H, (types.FunctionType, types.BuiltinFunctionType, partial)): res = _sesolve_func_td(H, rho0, tlist, e_ops, args, options, progress_bar) else: res = _sesolve_const(H, rho0, tlist, e_ops, args, options, progress_bar) if e_ops_dict: res.expect = { e: res.expect[n] for n, e in enumerate(e_ops_dict.keys()) } return res
def sesolve(H, rho0, tlist, e_ops=[], args={}, options=None, progress_bar=BaseProgressBar(), _safe_mode=True): """ Schrodinger equation evolution of a state vector for a given Hamiltonian. Evolve the state vector or density matrix (`rho0`) using a given Hamiltonian (`H`), by integrating the set of ordinary differential equations that define the system. The output is either the state vector at arbitrary points in time (`tlist`), or the expectation values of the supplied operators (`e_ops`). If e_ops is a callback function, it is invoked for each time in `tlist` with time and the state as arguments, and the function does not use any return values. Parameters ---------- H : :class:`qutip.qobj` system Hamiltonian, or a callback function for time-dependent Hamiltonians. rho0 : :class:`qutip.qobj` initial density matrix or state vector (ket). tlist : *list* / *array* list of times for :math:`t`. e_ops : list of :class:`qutip.qobj` / callback function single single operator or list of operators for which to evaluate expectation values. args : *dictionary* dictionary of parameters for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Qdeoptions` with options for the ODE solver. Returns ------- output: :class:`qutip.solver` An instance of the class :class:`qutip.solver`, which contains either an *array* of expectation values for the times specified by `tlist`, or an *array* or state vectors or density matrices corresponding to the times in `tlist` [if `e_ops` is an empty list], or nothing if a callback function was given inplace of operators for which to calculate the expectation values. """ if isinstance(e_ops, Qobj): e_ops = [e_ops] if isinstance(e_ops, dict): e_ops_dict = e_ops e_ops = [e for e in e_ops.values()] else: e_ops_dict = None if _safe_mode: _solver_safety_check(H, rho0, c_ops=[], e_ops=e_ops, args=args) # convert array based time-dependence to string format H, _, args = _td_wrap_array_str(H, [], args, tlist) # check for type (if any) of time-dependent inputs n_const, n_func, n_str = _td_format_check(H, []) if options is None: options = Options() if (not options.rhs_reuse) or (not config.tdfunc): # reset config time-dependence flags to default values config.reset() #check if should use OPENMP check_use_openmp(options) if n_func > 0: res = _sesolve_list_func_td(H, rho0, tlist, e_ops, args, options, progress_bar) elif n_str > 0: res = _sesolve_list_str_td(H, rho0, tlist, e_ops, args, options, progress_bar) elif isinstance(H, (types.FunctionType, types.BuiltinFunctionType, partial)): res = _sesolve_func_td(H, rho0, tlist, e_ops, args, options, progress_bar) else: res = _sesolve_const(H, rho0, tlist, e_ops, args, options, progress_bar) if e_ops_dict: res.expect = { e: res.expect[n] for n, e in enumerate(e_ops_dict.keys()) } return res
def sesolve(H, psi0, tlist, e_ops=[], args={}, options=None, progress_bar=None, _safe_mode=True): """ Schrodinger equation evolution of a state vector or unitary matrix for a given Hamiltonian. Evolve the state vector (`psi0`) using a given Hamiltonian (`H`), by integrating the set of ordinary differential equations that define the system. Alternatively evolve a unitary matrix in solving the Schrodinger operator equation. The output is either the state vector or unitary matrix at arbitrary points in time (`tlist`), or the expectation values of the supplied operators (`e_ops`). If e_ops is a callback function, it is invoked for each time in `tlist` with time and the state as arguments, and the function does not use any return values. e_ops cannot be used in conjunction with solving the Schrodinger operator equation Parameters ---------- H : :class:`qutip.qobj` system Hamiltonian, or a callback function for time-dependent Hamiltonians. psi0 : :class:`qutip.qobj` initial state vector (ket) or initial unitary operator `psi0 = U` tlist : *list* / *array* list of times for :math:`t`. e_ops : list of :class:`qutip.qobj` / callback function single single operator or list of operators for which to evaluate expectation values. Must be empty list operator evolution args : *dictionary* dictionary of parameters for time-dependent Hamiltonians options : :class:`qutip.Qdeoptions` with options for the ODE solver. progress_bar : BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. Returns ------- output: :class:`qutip.solver` An instance of the class :class:`qutip.solver`, which contains either an *array* of expectation values for the times specified by `tlist`, or an *array* or state vectors corresponding to the times in `tlist` [if `e_ops` is an empty list], or nothing if a callback function was given inplace of operators for which to calculate the expectation values. """ # check initial state: must be a state vector if _safe_mode: if not isinstance(psi0, Qobj): raise TypeError("psi0 must be Qobj") if psi0.isket: pass elif psi0.isunitary: if not e_ops == []: raise TypeError("Must have e_ops = [] when initial condition" " psi0 is a unitary operator.") else: raise TypeError("The unitary solver requires psi0 to be" " a ket as initial state" " or a unitary as initial operator.") _solver_safety_check(H, psi0, c_ops=[], e_ops=e_ops, args=args) if isinstance(e_ops, Qobj): e_ops = [e_ops] if isinstance(e_ops, dict): e_ops_dict = e_ops e_ops = [e for e in e_ops.values()] else: e_ops_dict = None if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() # convert array based time-dependence to string format H, _, args = _td_wrap_array_str(H, [], args, tlist) # check for type (if any) of time-dependent inputs n_const, n_func, n_str = _td_format_check(H, []) if options is None: options = Options() if (not options.rhs_reuse) or (not config.tdfunc): # reset config time-dependence flags to default values config.reset() #check if should use OPENMP check_use_openmp(options) if n_func > 0: res = _sesolve_list_func_td(H, psi0, tlist, e_ops, args, options, progress_bar) elif n_str > 0: res = _sesolve_list_str_td(H, psi0, tlist, e_ops, args, options, progress_bar) elif isinstance(H, (types.FunctionType, types.BuiltinFunctionType, partial)): res = _sesolve_func_td(H, psi0, tlist, e_ops, args, options, progress_bar) elif isinstance(H, Qobj): res = _sesolve_const(H, psi0, tlist, e_ops, args, options, progress_bar) else: raise TypeError("Invalid Hamiltonian specification") if e_ops_dict: res.expect = {e: res.expect[n] for n, e in enumerate(e_ops_dict.keys())} return res
def sesolve(H, rho0, tlist, e_ops, args={}, options=None, progress_bar=BaseProgressBar()): """ Schrodinger equation evolution of a state vector for a given Hamiltonian. Evolve the state vector or density matrix (`rho0`) using a given Hamiltonian (`H`), by integrating the set of ordinary differential equations that define the system. The output is either the state vector at arbitrary points in time (`tlist`), or the expectation values of the supplied operators (`e_ops`). If e_ops is a callback function, it is invoked for each time in `tlist` with time and the state as arguments, and the function does not use any return values. Parameters ---------- H : :class:`qutip.qobj` system Hamiltonian, or a callback function for time-dependent Hamiltonians. rho0 : :class:`qutip.qobj` initial density matrix or state vector (ket). tlist : *list* / *array* list of times for :math:`t`. e_ops : list of :class:`qutip.qobj` / callback function single single operator or list of operators for which to evaluate expectation values. args : *dictionary* dictionary of parameters for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Qdeoptions` with options for the ODE solver. Returns ------- output: :class:`qutip.solver` An instance of the class :class:`qutip.solver`, which contains either an *array* of expectation values for the times specified by `tlist`, or an *array* or state vectors or density matrices corresponding to the times in `tlist` [if `e_ops` is an empty list], or nothing if a callback function was given inplace of operators for which to calculate the expectation values. """ if isinstance(e_ops, Qobj): e_ops = [e_ops] if isinstance(e_ops, dict): e_ops_dict = e_ops e_ops = [e for e in e_ops.values()] else: e_ops_dict = None # convert array based time-dependence to string format H, _, args = _td_wrap_array_str(H, [], args, tlist) # check for type (if any) of time-dependent inputs n_const, n_func, n_str = _td_format_check(H, []) if options is None: options = Options() if (not options.rhs_reuse) or (not config.tdfunc): # reset config time-dependence flags to default values config.reset() if n_func > 0: res = _sesolve_list_func_td(H, rho0, tlist, e_ops, args, options, progress_bar) elif n_str > 0: res = _sesolve_list_str_td(H, rho0, tlist, e_ops, args, options, progress_bar) elif isinstance(H, (types.FunctionType, types.BuiltinFunctionType, partial)): res = _sesolve_func_td(H, rho0, tlist, e_ops, args, options, progress_bar) else: res = _sesolve_const(H, rho0, tlist, e_ops, args, options, progress_bar) if e_ops_dict: res.expect = {e: res.expect[n] for n, e in enumerate(e_ops_dict.keys())} return res