def _wigner_laguerre(rho, xvec, yvec, g, parallel): """ Using Laguerre polynomials from scipy to evaluate the Wigner function for the density matrices :math:`|m><n|`, :math:`W_{mn}`. The total Wigner function is calculated as :math:`W = \sum_{mn} \\rho_{mn} W_{mn}`. """ M = np.prod(rho.shape[0]) X, Y = meshgrid(xvec, yvec) A = 0.5 * g * (X + 1.0j * Y) W = zeros(np.shape(A)) # compute wigner functions for density matrices |m><n| and # weight by all the elements in the density matrix B = 4 * abs(A) ** 2 if sp.isspmatrix_csr(rho.data): # for compress sparse row matrices if parallel: iterator = ( (m, rho, A, B) for m in range(len(rho.data.indptr) - 1)) W1_out = parfor(_par_wig_eval, iterator) W += sum(W1_out) else: for m in range(len(rho.data.indptr) - 1): for jj in range(rho.data.indptr[m], rho.data.indptr[m + 1]): n = rho.data.indices[jj] if m == n: W += real(rho[m, m] * (-1) ** m * genlaguerre(m, 0)(B)) elif n > m: W += 2.0 * real(rho[m, n] * (-1) ** m * (2 * A) ** (n - m) * sqrt(factorial(m) / factorial(n)) * genlaguerre(m, n - m)(B)) else: # for dense density matrices B = 4 * abs(A) ** 2 for m in range(M): if abs(rho[m, m]) > 0.0: W += real(rho[m, m] * (-1) ** m * genlaguerre(m, 0)(B)) for n in range(m + 1, M): if abs(rho[m, n]) > 0.0: W += 2.0 * real(rho[m, n] * (-1) ** m * (2 * A) ** (n - m) * sqrt(factorial(m) / factorial(n)) * genlaguerre(m, n - m)(B)) return 0.5 * W * g ** 2 * np.exp(-B / 2) / pi
def _wigner_laguerre(rho, xvec, yvec, g, parallel): """ Using Laguerre polynomials from scipy to evaluate the Wigner function for the density matrices :math:`|m><n|`, :math:`W_{mn}`. The total Wigner function is calculated as :math:`W = \sum_{mn} \\rho_{mn} W_{mn}`. """ M = prod(rho.shape[0]) X, Y = meshgrid(xvec, yvec) A = 0.5 * g * (X + 1.0j * Y) W = zeros(np.shape(A)) # compute wigner functions for density matrices |m><n| and # weight by all the elements in the density matrix B = 4 * abs(A) ** 2 if sp.isspmatrix_csr(rho.data): # for compress sparse row matrices if parallel: iterator = ( (m, rho, A, B) for m in range(len(rho.data.indptr) - 1)) W1_out = parfor(_par_wig_eval, iterator) W += sum(W1_out) else: for m in range(len(rho.data.indptr) - 1): for jj in range(rho.data.indptr[m], rho.data.indptr[m + 1]): n = rho.data.indices[jj] if m == n: W += real(rho[m, m] * (-1) ** m * genlaguerre(m, 0)(B)) elif n > m: W += 2.0 * real(rho[m, n] * (-1) ** m * (2 * A) ** (n - m) * sqrt(factorial(m) / factorial(n)) * genlaguerre(m, n - m)(B)) else: # for dense density matrices B = 4 * abs(A) ** 2 for m in range(M): if abs(rho[m, m]) > 0.0: W += real(rho[m, m] * (-1) ** m * genlaguerre(m, 0)(B)) for n in range(m + 1, M): if abs(rho[m, n]) > 0.0: W += 2.0 * real(rho[m, n] * (-1) ** m * (2 * A) ** (n - m) * sqrt(factorial(m) / factorial(n)) * genlaguerre(m, n - m)(B)) return 0.5 * W * g ** 2 * np.exp(-B / 2) / pi
def mcsolve(H, psi0, tlist, c_ops, e_ops, ntraj=None, args={}, options=Options()): """Monte-Carlo evolution of a state vector :math:`|\psi \\rangle` for a given Hamiltonian and sets of collapse operators, and possibly, operators for calculating expectation values. Options for the underlying ODE solver are given by the Options class. mcsolve supports time-dependent Hamiltonians and collapse operators using either Python functions of strings to represent time-dependent coefficients. Note that, the system Hamiltonian MUST have at least one constant term. As an example of a time-dependent problem, consider a Hamiltonian with two terms ``H0`` and ``H1``, where ``H1`` is time-dependent with coefficient ``sin(w*t)``, and collapse operators ``C0`` and ``C1``, where ``C1`` is time-dependent with coeffcient ``exp(-a*t)``. Here, w and a are constant arguments with values ``W`` and ``A``. Using the Python function time-dependent format requires two Python functions, one for each collapse coefficient. Therefore, this problem could be expressed as:: def H1_coeff(t,args): return sin(args['w']*t) def C1_coeff(t,args): return exp(-args['a']*t) H=[H0,[H1,H1_coeff]] c_op_list=[C0,[C1,C1_coeff]] args={'a':A,'w':W} or in String (Cython) format we could write:: H=[H0,[H1,'sin(w*t)']] c_op_list=[C0,[C1,'exp(-a*t)']] args={'a':A,'w':W} Constant terms are preferably placed first in the Hamiltonian and collapse operator lists. Parameters ---------- H : qobj System Hamiltonian. psi0 : qobj Initial state vector tlist : array_like Times at which results are recorded. ntraj : int Number of trajectories to run. c_ops : array_like single collapse operator or ``list`` or ``array`` of collapse operators. e_ops : array_like single operator or ``list`` or ``array`` of operators for calculating expectation values. args : dict Arguments for time-dependent Hamiltonian and collapse operator terms. options : Options Instance of ODE solver options. Returns ------- results : Result Object storing all results from simulation. """ if debug: print(inspect.stack()[0][3]) if ntraj is None: ntraj = options.ntraj if not psi0.isket: raise Exception("Initial state must be a state vector.") 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 config.options = options if isinstance(ntraj, list): config.progress_bar = TextProgressBar(max(ntraj)) else: config.progress_bar = TextProgressBar(ntraj) # set num_cpus to the value given in qutip.settings if none in Options if not config.options.num_cpus: config.options.num_cpus = qutip.settings.num_cpus # set initial value data if options.tidy: config.psi0 = psi0.tidyup(options.atol).full().ravel() else: config.psi0 = psi0.full().ravel() config.psi0_dims = psi0.dims config.psi0_shape = psi0.shape # set options on ouput states if config.options.steady_state_average: config.options.average_states = True # set general items config.tlist = tlist if isinstance(ntraj, (list, ndarray)): config.ntraj = sort(ntraj)[-1] else: config.ntraj = ntraj # set norm finding constants config.norm_tol = options.norm_tol config.norm_steps = options.norm_steps # convert array based time-dependence to string format H, c_ops, args = _td_wrap_array_str(H, c_ops, args, tlist) # ---------------------------------------------- # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING # ---------------------------------------------- if (not options.rhs_reuse) or (not config.tdfunc): # reset config collapse and time-dependence flags to default values config.soft_reset() # check for type of time-dependence (if any) time_type, h_stuff, c_stuff = _td_format_check(H, c_ops, "mc") h_terms = len(h_stuff[0]) + len(h_stuff[1]) + len(h_stuff[2]) c_terms = len(c_stuff[0]) + len(c_stuff[1]) + len(c_stuff[2]) # set time_type for use in multiprocessing config.tflag = time_type # check for collapse operators if c_terms > 0: config.cflag = 1 else: config.cflag = 0 # Configure data _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options, config) # compile and load cython functions if necessary _mc_func_load(config) else: # setup args for new parameters when rhs_reuse=True and tdfunc is given # string based if config.tflag in array([1, 10, 11]): if any(args): config.c_args = [] arg_items = args.items() for k in range(len(args)): config.c_args.append(arg_items[k][1]) # function based elif config.tflag in array([2, 3, 20, 22]): config.h_func_args = args # load monte-carlo class mc = _MC_class(config) # RUN THE SIMULATION mc.run() # remove RHS cython file if necessary if not options.rhs_reuse and config.tdname: try: os.remove(config.tdname + ".pyx") except: pass # AFTER MCSOLVER IS DONE -------------------------------------- # ------- COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT -------------- output = Result() output.solver = "mcsolve" # state vectors if mc.psi_out is not None and config.options.average_states and config.cflag and ntraj != 1: output.states = parfor(_mc_dm_avg, mc.psi_out.T) elif mc.psi_out is not None: output.states = mc.psi_out # expectation values elif mc.expect_out is not None and config.cflag and config.options.average_expect: # averaging if multiple trajectories if isinstance(ntraj, int): output.expect = [mean([mc.expect_out[nt][op] for nt in range(ntraj)], axis=0) for op in range(config.e_num)] elif isinstance(ntraj, (list, ndarray)): output.expect = [] for num in ntraj: expt_data = mean(mc.expect_out[:num], axis=0) data_list = [] if any([not op.isherm for op in e_ops]): for k in range(len(e_ops)): if e_ops[k].isherm: data_list.append(np.real(expt_data[k])) else: data_list.append(expt_data[k]) else: data_list = [data for data in expt_data] output.expect.append(data_list) else: # no averaging for single trajectory or if average_states flag # (Options) is off if mc.expect_out is not None: output.expect = mc.expect_out # simulation parameters output.times = config.tlist output.num_expect = config.e_num output.num_collapse = config.c_num output.ntraj = config.ntraj output.col_times = mc.collapse_times_out output.col_which = mc.which_op_out if e_ops_dict: output.expect = {e: output.expect[n] for n, e in enumerate(e_ops_dict.keys())} return output
def mcsolve(H, psi0, tlist, c_ops, e_ops, ntraj=500, args={}, options=Odeoptions()): """Monte-Carlo evolution of a state vector :math:`|\psi \\rangle` for a given Hamiltonian and sets of collapse operators, and possibly, operators for calculating expectation values. Options for the underlying ODE solver are given by the Odeoptions class. mcsolve supports time-dependent Hamiltonians and collapse operators using either Python functions of strings to represent time-dependent coefficients. Note that, the system Hamiltonian MUST have at least one constant term. As an example of a time-dependent problem, consider a Hamiltonian with two terms ``H0`` and ``H1``, where ``H1`` is time-dependent with coefficient ``sin(w*t)``, and collapse operators ``C0`` and ``C1``, where ``C1`` is time-dependent with coeffcient ``exp(-a*t)``. Here, w and a are constant arguments with values ``W`` and ``A``. Using the Python function time-dependent format requires two Python functions, one for each collapse coefficient. Therefore, this problem could be expressed as:: def H1_coeff(t,args): return sin(args['w']*t) def C1_coeff(t,args): return exp(-args['a']*t) H=[H0,[H1,H1_coeff]] c_op_list=[C0,[C1,C1_coeff]] args={'a':A,'w':W} or in String (Cython) format we could write:: H=[H0,[H1,'sin(w*t)']] c_op_list=[C0,[C1,'exp(-a*t)']] args={'a':A,'w':W} Constant terms are preferably placed first in the Hamiltonian and collapse operator lists. Parameters ---------- H : qobj System Hamiltonian. psi0 : qobj Initial state vector tlist : array_like Times at which results are recorded. ntraj : int Number of trajectories to run. c_ops : array_like ``list`` or ``array`` of collapse operators. e_ops : array_like ``list`` or ``array`` of operators for calculating expectation values. args : dict Arguments for time-dependent Hamiltonian and collapse operator terms. options : Odeoptions Instance of ODE solver options. Returns ------- results : Odedata Object storing all results from simulation. """ if psi0.type != 'ket': raise Exception("Initial state must be a state vector.") odeconfig.options = options #set num_cpus to the value given in qutip.settings if none in Odeoptions if not odeconfig.options.num_cpus: odeconfig.options.num_cpus = qutip.settings.num_cpus #set initial value data if options.tidy: odeconfig.psi0 = psi0.tidyup(options.atol).full() else: odeconfig.psi0 = psi0.full() odeconfig.psi0_dims = psi0.dims odeconfig.psi0_shape = psi0.shape #set general items odeconfig.tlist = tlist if isinstance(ntraj, (list, ndarray)): odeconfig.ntraj = sort(ntraj)[-1] else: odeconfig.ntraj = ntraj #set norm finding constants odeconfig.norm_tol = options.norm_tol odeconfig.norm_steps = options.norm_steps #---- #---------------------------------------------- # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING #---------------------------------------------- if (not options.rhs_reuse) or (not odeconfig.tdfunc): #reset odeconfig collapse and time-dependence flags to default values _reset_odeconfig() #check for type of time-dependence (if any) time_type, h_stuff, c_stuff = _ode_checks(H, c_ops, 'mc') h_terms = len(h_stuff[0]) + len(h_stuff[1]) + len(h_stuff[2]) c_terms = len(c_stuff[0]) + len(c_stuff[1]) + len(c_stuff[2]) #set time_type for use in multiprocessing odeconfig.tflag = time_type #-Check for PyObjC on Mac platforms if sys.platform == 'darwin' and odeconfig.options.gui: try: import Foundation except: odeconfig.options.gui = False #check if running in iPython and using Cython compiling (then no GUI to work around error) if odeconfig.options.gui and odeconfig.tflag in array([1, 10, 11]): try: __IPYTHON__ except: pass else: odeconfig.options.gui = False if qutip.settings.qutip_gui == "NONE": odeconfig.options.gui = False #check for collapse operators if c_terms > 0: odeconfig.cflag = 1 else: odeconfig.cflag = 0 #Configure data _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options) if odeconfig.tflag in array([1, 10, 11]): #compile time-depdendent RHS code os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install( setup_args={'include_dirs': [numpy.get_include()]}) if odeconfig.tflag in array([1, 11]): code = compile( 'from ' + odeconfig.tdname + ' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs odeconfig.colspmv = col_spmv odeconfig.colexpect = col_expect else: code = compile( 'from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs try: os.remove(odeconfig.tdname + ".pyx") except: print("Error removing pyx file. File not found.") elif odeconfig.tflag == 0: odeconfig.tdfunc = cyq_ode_rhs else: #setup args for new parameters when rhs_reuse=True and tdfunc is given #string based if odeconfig.tflag in array([1, 10, 11]): if any(args): odeconfig.c_args = [] arg_items = args.items() for k in range(len(args)): odeconfig.c_args.append(arg_items[k][1]) #function based elif odeconfig.tflag in array([2, 3, 20, 22]): odeconfig.h_func_args = args #load monte-carlo class mc = _MC_class() #RUN THE SIMULATION mc.run() #AFTER MCSOLVER IS DONE -------------------------------------- #-------COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT --------------# output = Odedata() output.solver = 'mcsolve' #state vectors if mc.psi_out != None and odeconfig.options.mc_avg and odeconfig.cflag: output.states = parfor(_mc_dm_avg, mc.psi_out.T) elif mc.psi_out != None: output.states = mc.psi_out #expectation values elif mc.expect_out != None and odeconfig.cflag and odeconfig.options.mc_avg: #averaging if multiple trajectories if isinstance(ntraj, int): output.expect = mean(mc.expect_out, axis=0) elif isinstance(ntraj, (list, ndarray)): output.expect = [] for num in ntraj: expt_data = mean(mc.expect_out[:num], axis=0) data_list = [] if any([op.isherm == False for op in e_ops]): for k in range(len(e_ops)): if e_ops[k].isherm: data_list.append(real(expt_data[k])) else: data_list.append(expt_data[k]) else: data_list = [data for data in expt_data] output.expect.append(data_list) else: #no averaging for single trajectory or if mc_avg flag (Odeoptions) is off if mc.expect_out != None: output.expect = mc.expect_out #simulation parameters output.times = odeconfig.tlist output.num_expect = odeconfig.e_num output.num_collapse = odeconfig.c_num output.ntraj = odeconfig.ntraj output.col_times = mc.collapse_times_out output.col_which = mc.which_op_out return output
def mcsolve(H,psi0,tlist,c_ops,e_ops,ntraj=500,args={},options=Odeoptions()): """Monte-Carlo evolution of a state vector :math:`|\psi \\rangle` for a given Hamiltonian and sets of collapse operators, and possibly, operators for calculating expectation values. Options for the underlying ODE solver are given by the Odeoptions class. mcsolve supports time-dependent Hamiltonians and collapse operators using either Python functions of strings to represent time-dependent coefficients. Note that, the system Hamiltonian MUST have at least one constant term. As an example of a time-dependent problem, consider a Hamiltonian with two terms ``H0`` and ``H1``, where ``H1`` is time-dependent with coefficient ``sin(w*t)``, and collapse operators ``C0`` and ``C1``, where ``C1`` is time-dependent with coeffcient ``exp(-a*t)``. Here, w and a are constant arguments with values ``W`` and ``A``. Using the Python function time-dependent format requires two Python functions, one for each collapse coefficient. Therefore, this problem could be expressed as:: def H1_coeff(t,args): return sin(args['w']*t) def C1_coeff(t,args): return exp(-args['a']*t) H=[H0,[H1,H1_coeff]] c_op_list=[C0,[C1,C1_coeff]] args={'a':A,'w':W} or in String (Cython) format we could write:: H=[H0,[H1,'sin(w*t)']] c_op_list=[C0,[C1,'exp(-a*t)']] args={'a':A,'w':W} Constant terms are preferably placed first in the Hamiltonian and collapse operator lists. Parameters ---------- H : qobj System Hamiltonian. psi0 : qobj Initial state vector tlist : array_like Times at which results are recorded. ntraj : int Number of trajectories to run. c_ops : array_like single collapse operator or ``list`` or ``array`` of collapse operators. e_ops : array_like single operator or ``list`` or ``array`` of operators for calculating expectation values. args : dict Arguments for time-dependent Hamiltonian and collapse operator terms. options : Odeoptions Instance of ODE solver options. Returns ------- results : Odedata Object storing all results from simulation. """ # if single operator is passed for c_ops or e_ops, convert it to # list containing only that operator if isinstance(c_ops, Qobj): c_ops = [c_ops] if isinstance(e_ops, Qobj): e_ops = [e_ops] if psi0.type!='ket': raise Exception("Initial state must be a state vector.") odeconfig.options=options #set num_cpus to the value given in qutip.settings if none in Odeoptions if not odeconfig.options.num_cpus: odeconfig.options.num_cpus=qutip.settings.num_cpus #set initial value data if options.tidy: odeconfig.psi0=psi0.tidyup(options.atol).full() else: odeconfig.psi0=psi0.full() odeconfig.psi0_dims=psi0.dims odeconfig.psi0_shape=psi0.shape #set general items odeconfig.tlist=tlist if isinstance(ntraj,(list,ndarray)): odeconfig.ntraj=sort(ntraj)[-1] else: odeconfig.ntraj=ntraj #set norm finding constants odeconfig.norm_tol=options.norm_tol odeconfig.norm_steps=options.norm_steps #---- #---------------------------------------------- # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING #---------------------------------------------- if (not options.rhs_reuse) or (not odeconfig.tdfunc): #reset odeconfig collapse and time-dependence flags to default values _reset_odeconfig() #check for type of time-dependence (if any) time_type,h_stuff,c_stuff=_ode_checks(H,c_ops,'mc') h_terms=len(h_stuff[0])+len(h_stuff[1])+len(h_stuff[2]) c_terms=len(c_stuff[0])+len(c_stuff[1])+len(c_stuff[2]) #set time_type for use in multiprocessing odeconfig.tflag=time_type #-Check for PyObjC on Mac platforms if sys.platform=='darwin' and odeconfig.options.gui: try: import Foundation except: odeconfig.options.gui=False #check if running in iPython and using Cython compiling (then no GUI to work around error) if odeconfig.options.gui and odeconfig.tflag in array([1,10,11]): try: __IPYTHON__ except: pass else: odeconfig.options.gui=False if qutip.settings.qutip_gui=="NONE": odeconfig.options.gui=False #check for collapse operators if c_terms>0: odeconfig.cflag=1 else: odeconfig.cflag=0 #Configure data _mc_data_config(H,psi0,h_stuff,c_ops,c_stuff,args,e_ops,options) if odeconfig.tflag in array([1,10,11]): #compile time-depdendent RHS code os.environ['CFLAGS'] = '-O3 -w' import pyximport pyximport.install(setup_args={'include_dirs':[numpy.get_include()]}) if odeconfig.tflag in array([1,11]): code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc=cyq_td_ode_rhs odeconfig.colspmv=col_spmv odeconfig.colexpect=col_expect else: code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc=cyq_td_ode_rhs try: os.remove(odeconfig.tdname+".pyx") except: print("Error removing pyx file. File not found.") elif odeconfig.tflag==0: odeconfig.tdfunc=cyq_ode_rhs else:#setup args for new parameters when rhs_reuse=True and tdfunc is given #string based if odeconfig.tflag in array([1,10,11]): if any(args): odeconfig.c_args=[] arg_items=args.items() for k in range(len(args)): odeconfig.c_args.append(arg_items[k][1]) #function based elif odeconfig.tflag in array([2,3,20,22]): odeconfig.h_func_args=args #load monte-carlo class mc=_MC_class() #RUN THE SIMULATION mc.run() #AFTER MCSOLVER IS DONE -------------------------------------- #-------COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT --------------# output=Odedata() output.solver='mcsolve' #state vectors if mc.psi_out is not None and odeconfig.options.mc_avg and odeconfig.cflag: output.states=parfor(_mc_dm_avg,mc.psi_out.T) elif mc.psi_out is not None: output.states=mc.psi_out #expectation values elif mc.expect_out is not None and odeconfig.cflag and odeconfig.options.mc_avg:#averaging if multiple trajectories if isinstance(ntraj,int): output.expect=mean(mc.expect_out,axis=0) elif isinstance(ntraj,(list,ndarray)): output.expect=[] for num in ntraj: expt_data=mean(mc.expect_out[:num],axis=0) data_list=[] if any([op.isherm==False for op in e_ops]): for k in range(len(e_ops)): if e_ops[k].isherm: data_list.append(real(expt_data[k])) else: data_list.append(expt_data[k]) else: data_list=[data for data in expt_data] output.expect.append(data_list) else:#no averaging for single trajectory or if mc_avg flag (Odeoptions) is off if mc.expect_out is not None: output.expect=mc.expect_out #simulation parameters output.times=odeconfig.tlist output.num_expect=odeconfig.e_num output.num_collapse=odeconfig.c_num output.ntraj=odeconfig.ntraj output.col_times=mc.collapse_times_out output.col_which=mc.which_op_out return output