def _mesolve_list_td(H_func, rho0, tlist, c_op_list, e_ops, args, opt, progress_bar): """ Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fall back on the unitary schrodinger equation solver if len(c_op_list) == 0: return _sesolve_list_td(H_func, rho0, tlist, e_ops, args, opt, progress_bar) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError("Time-dependent Hamiltonian list must have two terms.") if not isinstance(H_func[0], (list, np.ndarray)) or len(H_func[0]) <= 1: raise TypeError("Time-dependent Hamiltonians must be a list " + "with two or more terms") if (not isinstance(H_func[1], (list, np.ndarray))) or (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError( "Time-dependent coefficients must be list with " + "length N-1 where N is the number of " + "Hamiltonian terms." ) if opt.rhs_reuse and config.tdfunc is None: rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian(H_func[0][m], [])) # create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += "Ldata[%d], Linds[%d], Lptrs[%d]," % (k, k, k) if args: td_consts = args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += "," # run code generator if not opt.rhs_reuse or config.tdfunc is None: if opt.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, config=config) cgen.generate(config.tdname + ".pyx") code = compile("from " + config.tdname + " import cy_td_ode_rhs", "<string>", "exec") exec(code, globals()) config.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(config.tdfunc) r.set_integrator( "zvode", method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step, ) r.set_initial_value(initial_vector, tlist[0]) code = compile("r.set_f_params(" + string + ")", "<string>", "exec") exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
def _sesolve_list_td(H_func, psi0, tlist, e_ops, args, opt, progress_bar): """! Evolve the wave function using an ODE solver with time-dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) if not isket(psi0): raise TypeError("psi0 must be a ket") # # configure time-dependent terms and setup ODE solver # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if (not isinstance(H_func[0], (list, np.ndarray))) or \ (len(H_func[0]) <= 1): raise TypeError('Time-dependent Hamiltonians must be a list with two ' + 'or more terms') if (not isinstance(H_func[1], (list, np.ndarray))) or \ (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError('Time-dependent coefficients must be list with ' + 'length N-1 where N is the number of ' + 'Hamiltonian terms.') tflag = 1 if opt.rhs_reuse and odeconfig.tdfunc is None: print("No previous time-dependent RHS found.") print("Generating one for you...") rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] # create data arrays for time-dependent RHS function Hdata = [-1.0j * H_func[0][k].data.data for k in range(lenh)] Hinds = [H_func[0][k].data.indices for k in range(lenh)] Hptrs = [H_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += ("Hdata[" + str(k) + "],Hinds[" + str(k) + "],Hptrs[" + str(k) + "],") if args: td_consts = args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") # run code generator if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = psi0.full().ravel() r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, psi0, tlist, e_ops, opt, progress_bar, norm, dims=psi0.dims)
def _mesolve_list_td(H_func, rho0, tlist, c_op_list, e_ops, args, opt, progress_bar): """! Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fall back on the unitary schrodinger equation solver if len(c_op_list) == 0: return _sesolve_list_td(H_func, rho0, tlist, e_ops, args, opt) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if not isinstance(H_func[0], (list, np.ndarray)) or len(H_func[0]) <= 1: raise TypeError('Time-dependent Hamiltonians must be a list ' + 'with two or more terms') if (not isinstance(H_func[1], (list, np.ndarray))) or \ (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError('Time-dependent coefficients must be list with ' + 'length N-1 where N is the number of ' + 'Hamiltonian terms.') if opt.rhs_reuse and odeconfig.tdfunc is None: rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian_fast(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian_fast(H_func[0][m], [])) # create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += ("Ldata[%d], Linds[%d], Lptrs[%d]," % (k, k, k)) if args: td_consts = args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") # run code generator if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
def _wfsolve_list_td(H_func, psi0, tlist, expt_ops,H_args, opt): """! Evolve the wave function using an ODE solver with time-dependent Hamiltonian. """ if not isket(psi0): raise TypeError("psi0 must be a ket") # # configure time-dependent terms and setup ODE solver # if len(H_func)!=2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if (not isinstance(H_func[0],(list,ndarray))) or (len(H_func[0])<=1): raise TypeError('Time-dependent Hamiltonians must be a list with two or more terms') if (not isinstance(H_func[1],(list,ndarray))) or (len(H_func[1])!=(len(H_func[0])-1)): raise TypeError('Time-dependent coefficients must be list with length ' + 'N-1 where N is the number of Hamiltonian terms.') tflag=1 if opt.rhs_reuse==True and odeconfig.tdfunc==None: print("No previous time-dependent RHS found.") print("Generating one for you...") rhs_generate(H_func,H_args) lenh=len(H_func[0]) if opt.tidy: H_func[0]=[(H_func[0][k]).tidyup() for k in range(lenh)] #create data arrays for time-dependent RHS function Hdata=[-1.0j*H_func[0][k].data.data for k in range(lenh)] Hinds=[H_func[0][k].data.indices for k in range(lenh)] Hptrs=[H_func[0][k].data.indptr for k in range(lenh)] #setup ode args string string="" for k in range(lenh): string+="Hdata["+str(k)+"],Hinds["+str(k)+"],Hptrs["+str(k)+"]," if H_args: td_consts=H_args.items() for elem in td_consts: string+=str(elem[1]) if elem!=td_consts[-1]: string+=(",") #run code generator if not opt.rhs_reuse or odeconfig.tdfunc == None: if opt.rhs_filename==None: odeconfig.tdname="rhs"+str(odeconfig.cgen_num) else: odeconfig.tdname=opt.rhs_filename cgen=Codegen(h_terms=n_L_terms,h_tdterms=Lcoeff, args=args) cgen.generate(odeconfig.tdname+".pyx") os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs':[numpy.get_include()]}) code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc=cyq_td_ode_rhs # # setup integrator # initial_vector = psi0.full() r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, #nsteps=opt.nsteps, #first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params('+string+')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, psi0, tlist, expt_ops, opt, lambda x: x)
def _mesolve_list_td(H_func, rho0, tlist, c_op_list, expt_ops, H_args, opt): """! Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ n_op = len(c_op_list) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fallback on the unitary schrodinger equation solver if n_op == 0: return _wfsolve_list_td(H_func, rho0, tlist, expt_ops, H_args, opt) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func)!=2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if (not isinstance(H_func[0],(list,ndarray))) or (len(H_func[0])<=1): raise TypeError('Time-dependent Hamiltonians must be a list with two or more terms') if (not isinstance(H_func[1],(list,ndarray))) or (len(H_func[1])!=(len(H_func[0])-1)): raise TypeError('Time-dependent coefficients must be list with length ' + 'N-1 where N is the number of Hamiltonian terms.') if opt.rhs_reuse==True and odeconfig.tdfunc==None: print("No previous time-dependent RHS found.") print("Generating one for you...") rhs_generate(H_func,H_args) lenh=len(H_func[0]) if opt.tidy: H_func[0]=[(H_func[0][k]).tidyup() for k in range(lenh)] L_func=[[liouvillian(H_func[0][0], c_op_list)],H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian(H_func[0][m],[])) #create data arrays for time-dependent RHS function Ldata=[L_func[0][k].data.data for k in range(lenh)] Linds=[L_func[0][k].data.indices for k in range(lenh)] Lptrs=[L_func[0][k].data.indptr for k in range(lenh)] #setup ode args string string="" for k in range(lenh): string+="Ldata["+str(k)+"],Linds["+str(k)+"],Lptrs["+str(k)+"]," if H_args: td_consts=H_args.items() for elem in td_consts: string+=str(elem[1]) if elem!=td_consts[-1]: string+=(",") #run code generator if not opt.rhs_reuse or odeconfig.tdfunc == None: if opt.rhs_filename==None: odeconfig.tdname="rhs"+str(odeconfig.cgen_num) else: odeconfig.tdname=opt.rhs_filename cgen=Codegen(h_terms=n_L_terms,h_tdterms=Lcoeff, args=args) cgen.generate(odeconfig.tdname+".pyx") os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs':[numpy.get_include()]}) code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc=cyq_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params('+string+')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, expt_ops, opt, vec2mat)
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 _mesolve_list_td(H_func, rho0, tlist, c_op_list, expt_ops, H_args, opt): """! Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ n_op = len(c_op_list) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fallback on the unitary schrodinger equation solver if n_op == 0: return _wfsolve_list_td(H_func, rho0, tlist, expt_ops, H_args, opt) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if (not isinstance(H_func[0], (list, ndarray))) or (len(H_func[0]) <= 1): raise TypeError( 'Time-dependent Hamiltonians must be a list with two or more terms' ) if (not isinstance(H_func[1], (list, ndarray))) or (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError( 'Time-dependent coefficients must be list with length ' + 'N-1 where N is the number of Hamiltonian terms.') if opt.rhs_reuse == True and odeconfig.tdfunc == None: print("No previous time-dependent RHS found.") print("Generating one for you...") rhs_generate(H_func, H_args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian(H_func[0][m], [])) #create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] #setup ode args string string = "" for k in range(lenh): string += "Ldata[" + str(k) + "],Linds[" + str(k) + "],Lptrs[" + str( k) + "]," if H_args: td_consts = H_args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") #run code generator if not opt.rhs_reuse or odeconfig.tdfunc == None: if opt.rhs_filename == None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args) cgen.generate(odeconfig.tdname + ".pyx") os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs': [numpy.get_include()]}) code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, expt_ops, opt, vec2mat)
def _wfsolve_list_td(H_func, psi0, tlist, expt_ops, H_args, opt): """! Evolve the wave function using an ODE solver with time-dependent Hamiltonian. """ if not isket(psi0): raise TypeError("psi0 must be a ket") # # configure time-dependent terms and setup ODE solver # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if (not isinstance(H_func[0], (list, ndarray))) or (len(H_func[0]) <= 1): raise TypeError( 'Time-dependent Hamiltonians must be a list with two or more terms' ) if (not isinstance(H_func[1], (list, ndarray))) or (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError( 'Time-dependent coefficients must be list with length ' + 'N-1 where N is the number of Hamiltonian terms.') tflag = 1 if opt.rhs_reuse == True and odeconfig.tdfunc == None: print("No previous time-dependent RHS found.") print("Generating one for you...") rhs_generate(H_func, H_args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] #create data arrays for time-dependent RHS function Hdata = [-1.0j * H_func[0][k].data.data for k in range(lenh)] Hinds = [H_func[0][k].data.indices for k in range(lenh)] Hptrs = [H_func[0][k].data.indptr for k in range(lenh)] #setup ode args string string = "" for k in range(lenh): string += "Hdata[" + str(k) + "],Hinds[" + str(k) + "],Hptrs[" + str( k) + "]," if H_args: td_consts = H_args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") #run code generator if not opt.rhs_reuse or odeconfig.tdfunc == None: if opt.rhs_filename == None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args) cgen.generate(odeconfig.tdname + ".pyx") os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs': [numpy.get_include()]}) code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = psi0.full() r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator( 'zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, #nsteps=opt.nsteps, #first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, psi0, tlist, expt_ops, opt, lambda x: x)
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 _mesolve_list_td(H_func, rho0, tlist, c_op_list, e_ops, args, opt, progress_bar): """! Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fall back on the unitary schrodinger equation solver if len(c_op_list) == 0: return _sesolve_list_td(H_func, rho0, tlist, e_ops, args, opt) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if not isinstance(H_func[0], (list, np.ndarray)) or len(H_func[0]) <= 1: raise TypeError('Time-dependent Hamiltonians must be a list ' + 'with two or more terms') if (not isinstance(H_func[1], (list, np.ndarray))) or \ (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError('Time-dependent coefficients must be list with ' + 'length N-1 where N is the number of ' + 'Hamiltonian terms.') if opt.rhs_reuse and odeconfig.tdfunc is None: rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian_fast(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian_fast(H_func[0][m], [])) # create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += ("Ldata[%d], Linds[%d], Lptrs[%d]," % (k, k, k)) if args: for name, value in args.items(): if isinstance(value, np.ndarray): globals()['var_%s'%name] = value string += 'var_%s,'%name else: string += str(value) + ',' # run code generator if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)