def _pyRHSc_with_state(t, psi, config): h_func_data = -1.0j * config.h_funcs(t, psi, config.h_func_args) h_func_term = spmv(h_func_data, psi) const_col_term = 0 if len(config.c_const_inds) > 0: const_col_term = spmv_csr(config.h_data, config.h_ind, config.h_ptr, psi) return h_func_term + const_col_term
def _tdRHStd(t, psi, config): const_term = spmv_csr(config.h_data, config.h_ind, config.h_ptr, psi) h_func_term = array( [ config.h_funcs[j](t, config.h_func_args) * spmv_csr(config.h_td_data[j], config.h_td_ind[j], config.h_td_ptr[j], psi) for j in config.h_td_inds ] ) col_func_terms = array( [ np.abs(config.c_funcs[j](t, config.c_func_args)) ** 2 * spmv_csr(config.n_ops_data[j], config.n_ops_ind[j], config.n_ops_ptr[j], psi) for j in config.c_td_inds ] ) return const_term - np.sum(h_func_term, 0) - 0.5 * np.sum(col_func_terms, 0)
def _cRHStd(t, psi, config): sys = cy_ode_rhs(t, psi, config.h_data, config.h_ind, config.h_ptr) col = np.array([np.abs(config.c_funcs[j](t, config.c_func_args)) ** 2 * spmv_csr(config.n_ops_data[j], config.n_ops_ind[j], config.n_ops_ptr[j], psi) for j in config.c_td_inds]) return sys - 0.5 * np.sum(col, 0)
def _pyRHSc_with_state(t, psi, config): h_func_data = - 1.0j * config.h_funcs(t, psi, config.h_func_args) h_func_term = spmv(h_func_data, psi) const_col_term = 0 if len(config.c_const_inds) > 0: const_col_term = spmv_csr(config.h_data, config.h_ind, config.h_ptr, psi) return h_func_term + const_col_term
def _tdRHStd(t, psi, config): const_term = spmv_csr(config.h_data, config.h_ind, config.h_ptr, psi) h_func_term = np.array([config.h_funcs[j](t, config.h_func_args) * spmv_csr(config.h_td_data[j], config.h_td_ind[j], config.h_td_ptr[j], psi) for j in config.h_td_inds]) col_func_terms = np.array([np.abs( config.c_funcs[j](t, config.c_func_args)) ** 2 * spmv_csr(config.n_ops_data[j], config.n_ops_ind[j], config.n_ops_ptr[j], psi) for j in config.c_td_inds]) return (const_term - np.sum(h_func_term, 0) - 0.5 * np.sum(col_func_terms, 0))
def _mc_alg_evolve(nt, config, opt, seeds): """ Monte Carlo algorithm returning state-vector or expectation values at times tlist for a single trajectory. """ global _cy_rhs_func global _cy_col_spmv_func, _cy_col_expect_func global _cy_col_spmv_call_func, _cy_col_expect_call_func tlist = config.tlist num_times = len(tlist) if not _cy_rhs_func: _mc_func_load(config) if config.options.steady_state_average: states_out = np.zeros((1), dtype=object) else: states_out = np.zeros((num_times), dtype=object) temp = sp.csr_matrix( np.reshape(config.psi0, (config.psi0.shape[0], 1)), dtype=complex) if (config.options.average_states and not config.options.steady_state_average): # output is averaged states, so use dm states_out[0] = Qobj(temp*temp.conj().transpose(), [config.psi0_dims[0], config.psi0_dims[0]], [config.psi0_shape[0], config.psi0_shape[0]], fast='mc-dm') elif (not config.options.average_states and not config.options.steady_state_average): # output is not averaged, so write state vectors states_out[0] = Qobj(temp, config.psi0_dims, config.psi0_shape, fast='mc') elif config.options.steady_state_average: states_out[0] = temp * temp.conj().transpose() # PRE-GENERATE LIST FOR EXPECTATION VALUES expect_out = [] for i in range(config.e_num): if config.e_ops_isherm[i]: # preallocate real array of zeros expect_out.append(np.zeros(num_times, dtype=float)) else: # preallocate complex array of zeros expect_out.append(np.zeros(num_times, dtype=complex)) expect_out[i][0] = \ cy_expect_psi_csr(config.e_ops_data[i], config.e_ops_ind[i], config.e_ops_ptr[i], config.psi0, config.e_ops_isherm[i]) collapse_times = [] which_oper = [] # SEED AND RNG AND GENERATE prng = RandomState(seeds[nt]) # first rand is collapse norm, second is which operator rand_vals = prng.rand(2) # CREATE ODE OBJECT CORRESPONDING TO DESIRED TIME-DEPENDENCE if config.tflag in [1, 10, 11]: ODE = ode(_cy_rhs_func) code = compile('ODE.set_f_params(' + config.string + ')', '<string>', 'exec') exec(code) elif config.tflag == 2: ODE = ode(_cRHStd) ODE.set_f_params(config) elif config.tflag in [20, 22]: if config.options.rhs_with_state: ODE = ode(_tdRHStd_with_state) else: ODE = ode(_tdRHStd) ODE.set_f_params(config) elif config.tflag == 3: if config.options.rhs_with_state: ODE = ode(_pyRHSc_with_state) else: ODE = ode(_pyRHSc) ODE.set_f_params(config) else: ODE = ode(_cy_rhs_func) ODE.set_f_params(config.h_data, config.h_ind, config.h_ptr) # initialize ODE solver for RHS ODE._integrator = qutip_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) if not len(ODE._y): ODE.t = 0.0 ODE._y = np.array([0.0], complex) ODE._integrator.reset(len(ODE._y), ODE.jac is not None) # set initial conditions ODE.set_initial_value(config.psi0, tlist[0]) # make array for collapse operator inds cinds = np.arange(config.c_num) # RUN ODE UNTIL EACH TIME IN TLIST for k in range(1, num_times): # ODE WHILE LOOP FOR INTEGRATE UP TO TIME TLIST[k] while ODE.t < tlist[k]: t_prev = ODE.t y_prev = ODE.y norm2_prev = dznrm2(ODE._y) ** 2 # integrate up to tlist[k], one step at a time. ODE.integrate(tlist[k], step=1) if not ODE.successful(): raise Exception("ZVODE failed!") norm2_psi = dznrm2(ODE._y) ** 2 if norm2_psi <= rand_vals[0]: # collapse has occured: # find collapse time to within specified tolerance # ------------------------------------------------ ii = 0 t_final = ODE.t while ii < config.norm_steps: ii += 1 t_guess = t_prev + \ np.log(norm2_prev / rand_vals[0]) / \ np.log(norm2_prev / norm2_psi) * (t_final - t_prev) ODE._y = y_prev ODE.t = t_prev ODE._integrator.call_args[3] = 1 ODE.integrate(t_guess, step=0) if not ODE.successful(): raise Exception( "ZVODE failed after adjusting step size!") norm2_guess = dznrm2(ODE._y)**2 if (np.abs(rand_vals[0] - norm2_guess) < config.norm_tol * rand_vals[0]): break elif (norm2_guess < rand_vals[0]): # t_guess is still > t_jump t_final = t_guess norm2_psi = norm2_guess else: # t_guess < t_jump t_prev = t_guess y_prev = ODE.y norm2_prev = norm2_guess if ii > config.norm_steps: raise Exception("Norm tolerance not reached. " + "Increase accuracy of ODE solver or " + "Options.norm_steps.") collapse_times.append(ODE.t) # some string based collapse operators if config.tflag in [1, 11]: n_dp = [cy_expect_psi_csr(config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE._y, 1) for i in config.c_const_inds] _locals = locals() # calculates the expectation values for time-dependent # norm collapse operators exec(_cy_col_expect_call_func, globals(), _locals) n_dp = np.array(_locals['n_dp']) elif config.tflag in [2, 20, 22]: # some Python function based collapse operators n_dp = [cy_expect_psi_csr(config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE._y, 1) for i in config.c_const_inds] n_dp += [abs(config.c_funcs[i]( ODE.t, config.c_func_args)) ** 2 * cy_expect_psi_csr(config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE._y, 1) for i in config.c_td_inds] n_dp = np.array(n_dp) else: # all constant collapse operators. n_dp = np.array( [cy_expect_psi_csr(config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE._y, 1) for i in range(config.c_num)]) # determine which operator does collapse and store it kk = np.cumsum(n_dp / np.sum(n_dp)) j = cinds[kk >= rand_vals[1]][0] which_oper.append(j) if j in config.c_const_inds: state = spmv_csr(config.c_ops_data[j], config.c_ops_ind[j], config.c_ops_ptr[j], ODE._y) else: if config.tflag in [1, 11]: _locals = locals() # calculates the state vector for collapse by a # time-dependent collapse operator exec(_cy_col_spmv_call_func, globals(), _locals) state = _locals['state'] else: state = \ config.c_funcs[j](ODE.t, config.c_func_args) * \ spmv_csr(config.c_ops_data[j], config.c_ops_ind[j], config.c_ops_ptr[j], ODE._y) state = state / dznrm2(state) ODE._y = state ODE._integrator.call_args[3] = 1 rand_vals = prng.rand(2) # after while loop # ---------------- out_psi = ODE._y / dznrm2(ODE._y) if config.e_num == 0 or config.options.store_states: out_psi_csr = sp.csr_matrix(np.reshape(out_psi, (out_psi.shape[0], 1)), dtype=complex) if (config.options.average_states and not config.options.steady_state_average): states_out[k] = Qobj( out_psi_csr * out_psi_csr.conj().transpose(), [config.psi0_dims[0], config.psi0_dims[0]], [config.psi0_shape[0], config.psi0_shape[0]], fast='mc-dm') elif config.options.steady_state_average: states_out[0] = ( states_out[0] + (out_psi_csr * out_psi_csr.conj().transpose())) else: states_out[k] = Qobj(out_psi_csr, config.psi0_dims, config.psi0_shape, fast='mc') for jj in range(config.e_num): expect_out[jj][k] = cy_expect_psi_csr( config.e_ops_data[jj], config.e_ops_ind[jj], config.e_ops_ptr[jj], out_psi, config.e_ops_isherm[jj]) # Run at end of mc_alg function # ----------------------------- if config.options.steady_state_average: states_out = np.array([Qobj(states_out[0] / float(len(tlist)), [config.psi0_dims[0], config.psi0_dims[0]], [config.psi0_shape[0], config.psi0_shape[0]], fast='mc-dm')]) return (states_out, expect_out, np.array(collapse_times, dtype=float), np.array(which_oper, dtype=int))
def _mc_alg_evolve(nt, args, config): """ Monte-Carlo algorithm returning state-vector or expectation values at times tlist for a single trajectory. """ global _cy_rhs_func global _cy_col_spmv_func, _cy_col_expect_func global _cy_col_spmv_call_func, _cy_col_expect_call_func if not _cy_rhs_func: _mc_func_load(config) try: # get input data mc_alg_out, opt, tlist, num_times, seeds = args collapse_times = [] # times of collapses which_oper = [] # which operator did the collapse # SEED AND RNG AND GENERATE prng = RandomState(seeds[nt]) # first rand is collapse norm, second is which operator rand_vals = prng.rand(2) # CREATE ODE OBJECT CORRESPONDING TO DESIRED TIME-DEPENDENCE if config.tflag in array([1, 10, 11]): ODE = ode(_cy_rhs_func) code = compile("ODE.set_f_params(" + config.string + ")", "<string>", "exec") exec(code) elif config.tflag == 2: ODE = ode(_cRHStd) ODE.set_f_params(config) elif config.tflag in array([20, 22]): if config.options.rhs_with_state: ODE = ode(_tdRHStd_with_state) else: ODE = ode(_tdRHStd) ODE.set_f_params(config) elif config.tflag == 3: if config.options.rhs_with_state: ODE = ode(_pyRHSc_with_state) else: ODE = ode(_pyRHSc) ODE.set_f_params(config) else: ODE = ode(_cy_rhs_func) ODE.set_f_params(config.h_data, config.h_ind, config.h_ptr) # initialize ODE solver for RHS ODE.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, ) # set initial conditions ODE.set_initial_value(config.psi0, tlist[0]) # make array for collapse operator inds cinds = np.arange(config.c_num) # RUN ODE UNTIL EACH TIME IN TLIST for k in range(1, num_times): # ODE WHILE LOOP FOR INTEGRATE UP TO TIME TLIST[k] while ODE.t < tlist[k]: t_prev = ODE.t y_prev = ODE.y norm2_prev = dznrm2(ODE.y) ** 2 # integrate up to tlist[k], one step at a time. ODE.integrate(tlist[k], step=1) if not ODE.successful(): raise Exception("ZVODE failed!") # check if ODE jumped over tlist[k], if so, # integrate until tlist exactly if ODE.t > tlist[k]: ODE.set_initial_value(y_prev, t_prev) ODE.integrate(tlist[k], step=0) if not ODE.successful(): raise Exception("ZVODE failed!") norm2_psi = dznrm2(ODE.y) ** 2 if norm2_psi <= rand_vals[0]: # <== collapse has occured # find collapse time to within specified tolerance # --------------------------------------------------- ii = 0 t_final = ODE.t while ii < config.norm_steps: ii += 1 t_guess = t_prev + np.log(norm2_prev / rand_vals[0]) / np.log(norm2_prev / norm2_psi) * ( t_final - t_prev ) ODE.set_initial_value(y_prev, t_prev) ODE.integrate(t_guess, step=0) if not ODE.successful(): raise Exception("ZVODE failed after adjusting step size!") norm2_guess = dznrm2(ODE.y) ** 2 if np.abs(rand_vals[0] - norm2_guess) < config.norm_tol * rand_vals[0]: break elif norm2_guess < rand_vals[0]: # t_guess is still > t_jump t_final = t_guess norm2_psi = norm2_guess else: # t_guess < t_jump t_prev = t_guess y_prev = ODE.y norm2_prev = norm2_guess if ii > config.norm_steps: raise Exception( "Norm tolerance not reached. " + "Increase accuracy of ODE solver or " + "Options.norm_steps." ) # --------------------------------------------------- collapse_times.append(ODE.t) # some string based collapse operators if config.tflag in array([1, 11]): n_dp = [ cy_expect_psi_csr(config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE.y, 1) for i in config.c_const_inds ] _locals = locals() # calculates the expectation values for time-dependent # norm collapse operators exec(_cy_col_expect_call_func, globals(), _locals) n_dp = array(_locals["n_dp"]) # some Python function based collapse operators elif config.tflag in array([2, 20, 22]): n_dp = [ cy_expect_psi_csr(config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE.y, 1) for i in config.c_const_inds ] n_dp += [ abs(config.c_funcs[i](ODE.t, config.c_func_args)) ** 2 * cy_expect_psi_csr( config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE.y, 1 ) for i in config.c_td_inds ] n_dp = array(n_dp) # all constant collapse operators. else: n_dp = array( [ cy_expect_psi_csr( config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE.y, 1 ) for i in range(config.c_num) ] ) # determine which operator does collapse and store it kk = cumsum(n_dp / sum(n_dp)) j = cinds[kk >= rand_vals[1]][0] which_oper.append(j) if j in config.c_const_inds: state = spmv_csr(config.c_ops_data[j], config.c_ops_ind[j], config.c_ops_ptr[j], ODE.y) else: if config.tflag in array([1, 11]): _locals = locals() # calculates the state vector for collapse by a # time-dependent collapse operator exec(_cy_col_spmv_call_func, globals(), _locals) state = _locals["state"] else: state = config.c_funcs[j](ODE.t, config.c_func_args) * spmv_csr( config.c_ops_data[j], config.c_ops_ind[j], config.c_ops_ptr[j], ODE.y ) state = state / dznrm2(state) ODE.set_initial_value(state, ODE.t) rand_vals = prng.rand(2) # ------------------------------------------------------- # -- after while loop -- out_psi = ODE.y / dznrm2(ODE.y) if config.e_num == 0: out_psi = sp.csr_matrix(np.reshape(out_psi, (out_psi.shape[0], 1)), dtype=complex) if config.options.average_states and not config.options.steady_state_average: mc_alg_out[k] = Qobj( out_psi * out_psi.conj().transpose(), [config.psi0_dims[0], config.psi0_dims[0]], [config.psi0_shape[0], config.psi0_shape[0]], fast="mc-dm", ) elif config.options.steady_state_average: mc_alg_out[0] = mc_alg_out[0] + (out_psi * out_psi.conj().transpose()) else: mc_alg_out[k] = Qobj(out_psi, config.psi0_dims, config.psi0_shape, fast="mc") else: for jj in range(config.e_num): mc_alg_out[jj][k] = cy_expect_psi_csr( config.e_ops_data[jj], config.e_ops_ind[jj], config.e_ops_ptr[jj], out_psi, config.e_ops_isherm[jj], ) # Run at end of mc_alg function # ------------------------------ if config.options.steady_state_average: mc_alg_out = array( [ Qobj( mc_alg_out[0] / float(len(tlist)), [config.psi0_dims[0], config.psi0_dims[0]], [config.psi0_shape[0], config.psi0_shape[0]], fast="mc-dm", ) ] ) return (nt, mc_alg_out, np.array(collapse_times, dtype=float), np.array(which_oper, dtype=int)) except Exception as e: print("failed to run _mc_alg_evolve: " + str(e))