def realization(H0, basis, psi_i, w, I, start, stop, num, endpoint, i): print i disorder = [[np.random.uniform(-w, w), i] for i in range(L)] Hl = hamiltonian([["n", disorder]], [], basis=H0.basis, dtype=np.float32, check_pcon=False, check_herm=False, check_symm=False) expH = exp_op(H0 + Hl, a=-1j, start=start, stop=stop, num=num, endpoint=endpoint, iterate=True) times = expH.grid psi_t = expH.dot(psi_i) obs = obs_vs_time( psi_t, times, {"I": I}, basis=basis) #,Sent_args=dict(sparse=True,sub_sys_A=[0])) try: return obs["I"], obs["Sent_time"]["Sent"] except KeyError: return obs["I"]
def Unitaries(delta_time, L, J, hz, action_min, var_max, var_min, state_i, save=False, save_str=''): # define Hamiltonian b = 0.0 lin_fun = lambda t: b H = Hamiltonian(L, fun=lin_fun, **{'J': J, 'hz': hz}) # number of unitaries n = int((var_max - var_min) / action_min) # preallocate dict expm_dict = {} for i in range(n + 1): # define matrix exponential; will be changed every time b is overwritten b = state_i[0] + i * action_min expm_dict[i] = np.asarray( exp_op(H, a=-1j * delta_time).get_mat().todense()) # calculate eigenbasis of H_target b = +2.0 _, V_target = H.eigh() if save: ### define save directory for data # read in local directory path str1 = os.getcwd() str2 = str1.split('\\') n = len(str2) my_dir = str2[n - 1] # create directory if non-existant save_dir = my_dir + "/unitaries" if not os.path.exists(save_dir): os.makedirs(save_dir) save_dir = "unitaries/" # save file dataname = save_dir + "unitaries_L={}".format(L) + save_str + '.pkl' cPickle.dump(expm_dict, open(dataname, "wb")) dataname = save_dir + "target_basis_L={}".format(L) + save_str + '.pkl' cPickle.dump(V_target, open(dataname, "wb")) else: return expm_dict
def precompute_expmatrix(param_SA, h_set, H): """ Purpose: Precomputes the evolution matrix and stores them in a global dictionary If unitary.dat is available, reads the matrices from this file """ L = param_SA['L'] J = param_SA['J'] hz = param_SA['hz'] hx_final_state = param_SA['hx_final_state'] delta_t = param_SA['delta_t'] import os.path from scipy.linalg import expm global matrix_dict file_name = ut.make_unitary_file_name(param_SA).replace( "SA", "unitaries/unitary") file_eigenvector = ut.make_unitary_file_name(param_SA).replace( "SA", "unitaries/eigenvector_FS") if os.path.isfile(file_name): with open(file_name, "rb") as f: matrix_dict = pickle.load(f) f.close() with open(file_eigenvector, "rb") as f: param_SA['V_target'] = pickle.load(f) else: matrix_dict = {} hx_dis_init = hx_discrete[0] for h in h_set: hx_discrete[0] = h # fix it later ! matrix_dict[h] = np.asarray( exp_op(H, a=-1j * delta_t).get_mat().todense()) # define matrix exponential # calculate final basis hx_discrete[0] = hx_final_state _, V_target = H.eigh() param_SA['V_target'] = V_target with open(file_eigenvector, "wb") as f: pickle.dump(V_target, f) f.close() hx_discrete[0] = hx_dis_init # resetting to it's original value with open(file_name, "wb") as f: pickle.dump(matrix_dict, f)
def realization(H_Heis, psi_0, basis, diag_op, times, real): """ This function computes the entropies for a single disorder realisation. --- arguments --- vs: vector of ramp speeds H_Heis: static Heisenberg Hamiltonian basis: spin_basis_1d object containing the spin basis n_real: number of disorder realisations; used only for timing """ ti = time() # get start time # seed() # the random number needs to be seeded for each parallel process # # draw random field uniformly from [-1.0,1.0] for each lattice site unscaled_fields = -1 + 2 * ranf((basis.L, )) # define z-field operator site-coupling list h_z = [[unscaled_fields[i], i] for i in range(basis.L)] # static list disorder_field = [["z", h_z]] # compute disordered z-field Hamiltonian no_checks = {"check_herm": False, "check_pcon": False, "check_symm": False} Hz = hamiltonian(disorder_field, [], basis=basis, dtype=np.float64, **no_checks) # compute the MBL and ETH Hamiltonians for the same disorder realisation H_MBL = H_Heis + h_MBL * Hz # expO = exp_op(H_MBL) psi_t = psi_0 time_old = 0 imb = [] # Sent=[] # sub_sizes=[1,2,3] for a_time in times: expO.set_a(-1j * (a_time - time_old)) time_old = a_time psi_t = expO.dot(psi_t) imb.append(np.einsum('i,i,i', np.conj(psi_t), diag_op, psi_t)) # Sent.append([map(lambda x: ent_entropy(psi_t,basis,chain_subsys=range(x,x+size))["Sent"],range(basis.L-size+1)) for size in sub_sizes]) # imb_at_t = lambda time: diag_op_exp(expO,psi_0,diag_op,time) # imb = list(map(imb_at_t,times)) # imb = list(map(imb_at_t,times)) # show time taken print("realization {0}/{1} took {2:.2f} sec".format( real + 1, n_real, time() - ti)) # return np.real(imb)
def Fidelity(psi_i,H,N_time_step,delta_t,psi_target,option='standard'): """ Purpose: Calculates final fidelity by evolving psi_i over a N_time_step Return: Norm squared between the target state psi_target and the evolved state (according to the full hx_discrete protocol) """ if option is 'standard': psi_evolve=psi_i.copy() for t in range(N_time_step): psi_evolve = exp_op(H(time=t),a=-1j*delta_t).dot(psi_evolve) return abs(np.sum(np.conj(psi_evolve)*psi_target))**2 else: return fast_Fidelity(psi_i,H,N_time_step,delta_t,psi_target)
def real(H_dict,I,psi_0,w,t,i): # body of function goes below ti = time() # start timing function for duration of reach realisation # create a parameter list which specifies the onsite potential with disorder params_dict=dict(H0=1.0) for j in range(L): params_dict["n"+str(j)] = uniform(-w,w) # using the parameters dictionary construct a hamiltonian object with those # parameters defined in the list H = H_dict.tohamiltonian(params_dict) # use exp_op to get the evolution operator U = exp_op(H,a=-1j,start=t.min(),stop=t.max(),num=len(t),iterate=True) psi_t = U.dot(psi_0) # get generator psi_t for time evolved state # use obs_vs_time to evaluate the dynamics t = U.grid # extract time grid stored in U, and defined in exp_op obs_t = obs_vs_time(psi_t,t,dict(I=I)) # print reporting the computation time for realization print("realization {}/{} completed in {:.2f} s".format(i+1,n_real,time()-ti)) # return observable values return obs_t["I"]
def Fidelity(psi_i, H_fid, t_vals, delta_t, psi_f=None, all_obs=False, Vf=None): ''' This function calculates the physical quantities given a time-dep Hamiltonian H_fid. If psi_f is not given, then it returns the fidelity in the instantaneous eigenstate, otherwise --- the fidelity in the final state. ''' basis = H_fid.basis # evolve state #psi_t = H_fid.evolve(psi_i,t_vals[0],t_vals,iterate=True,atol=1E-12,rtol=1E-12) # fidelity fid = [] if all_obs: # get sysstem size L = basis.L # entanglement entropy density Sent = [] subsys = [j for j in range(L / 2)] # energy E = [] # energy fluctuations dE = [] Sd = [] psi = psi_i.copy() for i, t_i in enumerate(t_vals): #for i, psi in enumerate(psi_t): psi = exp_op(H_fid(time=t_i), a=-1j * delta_t).dot(psi) if psi_f is not None: # calculate w.r.t. final state psi_target = psi_f else: # calculate w.r.t. instantaneous state _, psi_inst = H_fid.eigsh(time=t_vals[i], k=1, sigma=-100.0) psi_target = psi_inst.squeeze() fid.append(abs(psi.conj().dot(psi_target))**2) #print i, abs(psi.conj().dot(psi_target))**2 if all_obs: if L > 1: EGS, _ = H_fid.eigsh(time=t_vals[i], k=2, which='BE', maxiter=1E10, return_eigenvectors=False) else: EGS = H_fid.eigvalsh(time=t_vals[i])[0] E.append( H_fid.matrix_ele(psi, psi, time=t_vals[i]).real / L - EGS / L) if i == 0: dE.append(0.0) else: dE.append( np.sqrt((H_fid * H_fid(time=t_vals[i])).matrix_ele( psi, psi, time=t_vals[i]).real / L**2 - E[i]**2)) #print H_fid2.matrix_ele(psi,psi,time=t_vals[i]).real/L**2 - E[i]**2 pn = abs(Vf.conj().T.dot(psi))**2.0 + np.finfo(psi[0].dtype).eps Sd.append(-pn.dot(np.log(pn)) / L) if basis.L != 1: Sent.append( ent_entropy(psi, basis, chain_subsys=subsys)['Sent']) else: Sent.append(float('nan')) if not all_obs: return fid else: return fid, E, dE, Sent, Sd
def Q_learning(RL_params, physics_params, theta=None, tilings=None, greedy=False): #################################################################### start_time = time.time() #################################################################### # display full strings np.set_printoptions(threshold='nan') ###################################################################### ####################### read off params ######################### ###################################################################### # read off RL_params RL_keys = [ 'N_episodes', 'alpha_0', 'eta', 'lmbda', 'beta_RL', 'traces', 'dims', 'N_tiles', 'state_i', 'h_field', 'dh_field' ] from numpy import array for key, value in RL_params.iteritems(): #print key, repr(value) if key not in RL_keys: raise TypeError( "Key '{}' not allowed for use in dictionary!".format(key)) # turn key to variable and assign its value exec("{} = {}".format(key, repr(value))) in locals() # read off physics params physics_keys = [ 'L', 'max_t_steps', 'delta_t', 'J', 'hz', 'hx_i', 'hx_f', 'psi_i', 'psi_f', 'E_i', 'E_f' ] for key, value in physics_params.iteritems(): #print key, repr(value) if key not in physics_keys: raise TypeError( "Key '{}' not allowed for use in dictionary!".format(key)) # turn key to variable and assign its value exec("{} = {}".format(key, repr(value))) in locals() ###################################################################### # define all actions actions = RL.all_actions() # eta limits # max and min field hx_limits = [h_field[0], h_field[-1]] # get dimensions N_tilings, N_lintiles, N_vars = dims N_tiles = N_lintiles**N_vars N_actions = len(actions) shift_tile_inds = [j * N_tiles for j in xrange(N_tilings)] if theta is None: theta = np.zeros((N_tiles * N_tilings, max_t_steps, N_actions), dtype=np.float64) if tilings is None: tilings = RL.gen_tilings(h_field, dh_field, N_tilings) # pre-allocate traces variable e = np.zeros_like(theta) fire_trace = np.ones(N_tilings) if not greedy: # pre-allocate usage vector: inverse gradient descent learning rate u0 = 1.0 / alpha_0 * np.ones((N_tiles * N_tilings, ), dtype=np.float64) else: u0 = np.inf * np.ones((N_tiles * N_tilings, ), dtype=np.float64) u = np.zeros_like(u0) #### physical quantities # define ED Hamiltonian H(t) b = hx_i lin_fun = lambda t: b #+ m*t # define Hamiltonian H = Hamiltonian.Hamiltonian(L, fun=lin_fun, **{'J': J, 'hz': hz}) # define matrix exponential exp_H = exp_op(H, a=-1j * delta_t) #""" ''' will not need onless we plot ''' # defien Hamiltonian for any step-lie protocol p_vals at times t_vals t_vals, p_vals = [0.0, 0.0], [0.0, 0.0] def step_protocol(t): return p_vals[np.argmin(abs(np.asarray(t_vals) - t))] H_fid = Hamiltonian.Hamiltonian(L, fun=step_protocol, **{'J': J, 'hz': hz}) # calculate final basis b = hx_f _, Vf = H.eigh(time=0.0) b = hx_i ''' will not need ''' #""" # average reward Return_ave = np.zeros((N_episodes, 1), dtype=np.float64) Return = Return_ave.copy() Fidelity_ep = Return_ave.copy() # initialise best fidelity best_fidelity = 0.0 # best encountered fidelity # set of actions for best encountered protocol best_actions = [random.choice(actions) for j in range(max_t_steps)] # calculate importance sampling ratio R = 0.0 # instantaneous fidelity psi = np.zeros_like(psi_i) # loop over episodes for ep in xrange(N_episodes): # set traces to zero e *= 0.0 # set initial usage vector u[:] = u0[:] # set initial state of episode S = state_i.copy() # get set of features present in S theta_inds = RL.find_feature_inds(S, tilings, shift_tile_inds) Q = np.sum(theta[theta_inds, 0, :], axis=0) # for each action at time t_step=0 # preallocate physical quantties psi[:] = psi_i[:] # quantum state at time protocol_inst = [] t_inst = [] # calculate fidelity for each fixed episode Return_ep = 0.0 # taken encountered and taken actions_taken = [] # generate episode for t_step in xrange(max_t_steps): # # calculate available actions from state S avail_inds = np.argwhere( (S[0] + np.array(actions) <= hx_limits[1]) * (S[0] + np.array(actions) >= hx_limits[0])).squeeze() avail_actions = [actions[_j] for _j in avail_inds] # calculate greedy action(s) wrt Q policy A_greedy = avail_actions[random.choice( np.argwhere(Q[avail_inds] == np.amax(Q[avail_inds])).ravel())] # choose a random action P = np.exp(beta_RL * Q[avail_inds]) p = np.cumsum(P / sum(P)) if greedy or beta_RL > 1E12: A = A_greedy else: A = avail_actions[np.searchsorted(p, random.uniform(0.0, 1.0))] # find the index of A indA = actions.index(A) # reset traces if A is exploratory if abs(A - A_greedy) > np.finfo(A).eps: e *= 0.0 # take action A, return state S_prime and actual reward R ################################################################################ ###################### INTERACT WITH ENVIRONMENT ######################### ################################################################################ # define new state S_prime = S.copy() # calculate new field value S_prime[0] += A ### assign reward R *= 0.0 # all physics happens here # update dynamic arguments in place: ramp = m*t+b b = S_prime[0] psi = exp_H.dot(psi) # assign reward if t_step == max_t_steps - 1: # calculate final fidelity fidelity = abs(psi.conj().dot(psi_f))**2 # reward R += fidelity ################################################################################ ################################################################################ ################################################################################ # update episodic return Return_ep += R # update protocol and time protocol_inst.append(S_prime[0]) t_inst.append(t_step * delta_t) # record action taken actions_taken.append(A) ############################ # calculate usage and alpha vectors: alpha_inf = eta u[theta_inds] *= (1.0 - eta) u[theta_inds] += 1.0 alpha = 1.0 / (N_tilings * u[theta_inds]) # Q learning update rule; GD error in time t delta = R - Q[indA] # error in gradient descent # TO Q_old = theta[theta_inds, t_step, indA].sum() # update traces e[theta_inds, t_step, indA] = alpha * fire_trace # check if S_prime is terminal or went out of grid if t_step == max_t_steps - 1: # update theta theta += delta * e # GD error in field h delta_TO = Q_old - theta[theta_inds, t_step, indA].sum() theta[theta_inds, t_step, indA] += alpha * delta_TO # go to next episode break # get set of features present in S_prime theta_inds_prime = RL.find_feature_inds(S_prime, tilings, shift_tile_inds) # t-dependent Watkin's Q learning Q = np.sum(theta[theta_inds_prime, t_step + 1, :], axis=0) # update theta delta += max(Q) theta += delta * e # GD error in field h delta_TO = Q_old - theta[theta_inds, t_step, indA].sum() theta[theta_inds, t_step, indA] += alpha * delta_TO # update traces e[theta_inds, t_step, indA] -= alpha * e[theta_inds, t_step, indA].sum() e *= lmbda ################################ # S <- S_prime S[:] = S_prime[:] theta_inds[:] = theta_inds_prime[:] if greedy: return protocol_inst, t_inst # save average return Return_ave[ep] = 1.0 / (ep + 1) * (Return_ep + ep * Return_ave[ep - 1]) Return[ep] = Return_ep Fidelity_ep[ep] = fidelity # if greedy policy completes a full episode and if greedy fidelity is worse than inst one if fidelity - best_fidelity > 1E-12: # update list of best actions best_actions[:] = actions_taken[:] # calculate best protocol and fidelity protocol_best, t_best = best_protocol(best_actions, hx_i, delta_t) R_best = R best_fidelity = fidelity theta = Learn_Policy(state_i, theta, tilings, dims, best_actions, R_best) #theta = Replay(50,RL_params,physics_params,theta,tilings,best_actions,R_best) # force-learn best encountered every 100 episodes if (ep % 40 == 0 and ep != 0) and (R_best is not None) and beta_RL < 1E12: print 'learned best encountered' theta = Learn_Policy(state_i, theta, tilings, dims, best_actions, R_best) #theta = Replay(50,RL_params,physics_params,theta,tilings,best_actions,R_best) #''' if ep % 20 == 0: print "finished simulating episode {} with fidelity {} at hx_f = {}.".format( ep + 1, np.round(fidelity, 3), S_prime[0]) print 'best encountered fidelity is {}.'.format( np.round(best_fidelity, 3)) #''' #''' # plot protocols and learning rate if (ep % 500 == 0 and ep != 0) or (np.round(fidelity, 3) == 1.0): RL_params['beta_RL'] = 1E12 RL_params['lmbda'] = 0.0 RL_params['alpha_0'] = 0.0 # fig file name params save = False #True save_vars = ['J', 'hz', 'hxi', 'hxf', 'Ei', 'Ef', 'Neps'] save_vals = truncate([J, hz, hx_i, hx_f, E_i / L, E_f / L, j], 2) save_params = "_L={}".format(L) + "".join( ['_' + i + '=' + k for i, k in zip(save_vars, save_vals)]) # calculate greedy fidelity Q_args = (RL_params, physics_params) Q_kwargs = {'theta': theta, 'tilings': tilings} protocol_greedy, t_greedy = Q_learning(*Q_args, greedy=True, **Q_kwargs) # calculate inst fidelities of interpolated protocols t_vals, p_vals = t_inst, protocol_inst F_inst, E_inst, dE_inst, Sent_inst, Sd_inst = Fidelity( psi_i, H_fid, t_vals, delta_t, psi_f=psi_f, all_obs=True, Vf=Vf) t_vals, p_vals = t_greedy, protocol_greedy F_greedy, E_greedy, dE_greedy, Sent_greedy, Sd_greedy = Fidelity( psi_i, H_fid, t_vals, delta_t, psi_f=psi_f, all_obs=True, Vf=Vf) t_vals, p_vals = t_best, protocol_best F_best, E_best, dE_best, Sent_best, Sd_best = Fidelity( psi_i, H_fid, t_vals, delta_t, psi_f=psi_f, all_obs=True, Vf=Vf) # prepare plot data times = [t_inst, t_greedy, t_best] protocols = [protocol_inst, protocol_greedy, protocol_best] fidelities = [F_inst, F_greedy, F_best] energies = [E_inst, E_greedy, E_best] d_energies = [dE_inst, dE_greedy, dE_best] s_ents = [Sent_inst, Sent_greedy, Sent_best] s_ds = [Sd_inst, Sd_greedy, Sd_best] Data = np.zeros((7, max_t_steps)) Data[0, :] = t_best Data[1, :] = protocol_best Data[2, :] = F_best Data[3, :] = E_best Data[4, :] = dE_best Data[5, :] = Sent_best Data[6, :] = Sd_best # plot data user_input = raw_input("continue? (y or n) ") if user_input == 'y': # plot rewards #plot_rewards(N_episodes,Return_ave,Return,Fidelity_ep,'rewards',save_params,save) # plot protocols plot_protocols(times, protocols, fidelities, 'fidelity', save_params, save) #plot_protocols(times,protocols,energies,'energy',save_params,save) #plot_protocols(times,protocols,d_energies,'energy fluct.',save_params,save) #plot_protocols(times,protocols,s_ents,'ent. entropy',save_params,save) #plot_protocols(times,protocols,s_ds,'diag. entropy',save_params,save) """ # calculate approximate Q function etas = np.linspace(hx_limits[0],hx_limits[1],101) #etas = np.linspace(-1.0,1.0,101) Q_plot = RL.Q_greedy(etas,theta,tilings,shift_tile_inds,max_t_steps).T plot_Q(etas,t_best,-Q_plot,'Q_fn',save_params,save) """ if save: user_input = raw_input("save data? (y or n) ") if user_input == 'y': args = (L, ) + tuple(np.around([J, hz, hx_i, hx_f], 2)) dataname = "best_L=%s_J=%s_hz=%s_hxi=%s_hxf=%s.txt" % args np.savetxt(dataname, Data.T) RL_params['beta_RL'] = beta_RL RL_params['lmbda'] = lmbda RL_params['alpha_0'] = alpha_0 #''' print "Calculating the Q function loop using Q-Learning took", ( "--- %s seconds ---" % (time.time() - start_time))
n_1=hamiltonian(n_1_static,[],basis=basis,dtype=np.float64, check_herm=False,check_pcon=False) # construct operator n_2 = $n_{j=L/2}$ n_2_static=[['n',[[1.0,L//2]]]] n_2=hamiltonian(n_2_static,[],basis=basis,dtype=np.float64, check_herm=False,check_pcon=False) # transform n_j operators to momentum space n_1=n_1.rotate_by(FT,generator=False) n_2=n_2.rotate_by(FT,generator=False) ##### evaluate nonequal time correlator <FS|n_2(t) n_1(0)|FS> ##### # define time vector t=np.linspace(0.0,90.0,901) # calcualte state acted on by n_1 n_psi0=n_1.dot(psi0) # construct time-evolution operator using exp_op class (sometimes faster) U = exp_op(Hblock,a=-1j,start=t.min(),stop=t.max(),num=len(t),iterate=True) # evolve states psi_t=U.dot(psi0) n_psi_t = U.dot(n_psi0) # alternative method for time evolution using Hamiltonian class #psi_t=Hblock.evolve(psi0,0.0,t,iterate=True) #n_psi_t=Hblock.evolve(n_psi0,0.0,t,iterate=True) # preallocate variable correlators=np.zeros(t.shape+psi0.shape[1:]) # loop over the time-evolved states for i, (psi,n_psi) in enumerate( zip(psi_t,n_psi_t) ): correlators[i,:]=n_2.matrix_ele(psi,n_psi,diagonal=True).real # evaluate correlator at finite temperature n_FD=1.0/(np.exp(beta*E)+1.0) correlator = (n_FD*correlators).sum(axis=-1) ##### plot spectra
w = 0.0 t = -1.0 * np.exp(-1j * a * np.pi) J = [[t, i, (i + 1) % L] for i in range(L - 1)] J_cc = [[t.conjugate(), i, (i + 1) % L] for i in range(L - 1)] V = [[np.random.uniform(-w, w) + 0.01 * i, i] for i in range(L - 1)] static = [["+-", J], ["-+", J_cc], ["n", V]] H = hamiltonian(static, [], basis=basis) sites = np.arange(L) psi = np.exp(-(sites - L / 4)**2 / float(L / 10)) psi /= np.linalg.norm(psi) psi_t = exp_op(H, a=-1j, start=0, stop=1000000, num=100000, iterate=True).dot(psi) psi = next(psi_t) ns = np.abs(psi)**2 fig = plt.figure() ax = plt.gca() line, = ax.plot(sites, ns, marker="") def updatefig(i): psi = next(psi_t) ns = np.abs(psi)**2 line.set_data(sites, ns) return line,
# ###### calculate initial states ###### # calculating bandwidth for non-driven hamiltonian [E_1d_min], psi_1d = Hzz_1d.eigsh(k=1, which="SA") [E_2d_min], psi_2d = Hzz_2d.eigsh(k=1, which="SA") # setting up initial states psi0_1d = psi_1d.ravel() psi0_2d = psi_2d.ravel() # ###### time evolution ###### # stroboscopic time vector nT = 200 # number of periods to evolve to t = Floquet_t_vec(Omega, nT, len_T=1) # t.vals=t, t.i=initial time, t.T=drive period # creating generators of time evolution using exp_op class U1_1d = exp_op(Hzz_1d + A * Hx_1d, a=-1j * t.T / 4) U2_1d = exp_op(Hzz_1d - A * Hx_1d, a=-1j * t.T / 2) U1_2d = exp_op(Hzz_2d + A * Hx_2d, a=-1j * t.T / 4) U2_2d = exp_op(Hzz_2d - A * Hx_2d, a=-1j * t.T / 2) # user-defined generator for stroboscopic dynamics def evolve_gen(psi0, nT, *U_list): yield psi0 for i in range(nT): # loop over number of periods for U in U_list: # loop over unitaries psi0 = U.dot(psi0) yield psi0 # get generator objects for time-evolved states
def test(): L = 5 start = 0 stop = 10 num = 10 J = [[1.0, i, (i + 1) % L] for i in range(L)] h = [[1.0, i] for i in range(L)] static = [["xx", J], ["yy", J], ["zz", J]] dynamic = [["z", h, np.sin, ()]] blocks = [] for Nup in range(L + 1): blocks.append({"Nup": Nup}) H_block = block_diag_hamiltonian(blocks, static, dynamic, spin_basis_1d, (L, ), np.float64) H = hamiltonian(static, dynamic, N=L) for t in np.linspace(0, 2 * np.pi): E = H.eigvalsh(time=t) E_blocks = H.eigvalsh(time=t) np.testing.assert_allclose(E, E_blocks) static = [["zz", J]] dynamic = [["x", h, f, []]] blocks = [] for kblock in range(L): blocks.append({"kblock": kblock}) H = hamiltonian(static, dynamic, N=L) [E0] = H.eigsh(time=0.3, k=1, which='SA', return_eigenvectors=False) block_op = block_ops(blocks, static, dynamic, spin_basis_1d, (L, ), np.complex128, compute_all_blocks=True) # real time. expH = exp_op(H, a=-1j, start=start, stop=stop, iterate=True, num=num, endpoint=True) times = np.linspace(start, stop, num=num, endpoint=True) psi0 = np.random.ranf(H.Ns) psi0 /= np.linalg.norm(psi0) psi_exact_1 = H.evolve(psi0, 0, times, iterate=True, atol=1e-15, rtol=1e-15) psi_block_1 = block_op.evolve(psi0, 0, times, iterate=True, atol=1e-15, rtol=1e-15, n_jobs=4) psi_exact_2 = expH.dot(psi0, time=0.3) psi_block_2 = block_op.expm(psi0, H_time_eval=0.3, start=start, stop=stop, iterate=True, num=num, endpoint=True, n_jobs=2, block_diag=True) for psi_e_1, psi_e_2, psi_b_1, psi_b_2 in izip(psi_exact_1, psi_exact_2, psi_block_1, psi_block_2): np.testing.assert_allclose(psi_b_1, psi_e_1, atol=1e-7) np.testing.assert_allclose(psi_b_2, psi_e_2, atol=1e-7) expH.set_iterate(False) psi_exact_1 = H.evolve(psi0, 0, times, iterate=False, atol=1e-15, rtol=1e-15) psi_block_1 = block_op.evolve(psi0, 0, times, iterate=False, atol=1e-15, rtol=1e-15, n_jobs=4) psi_exact_2 = expH.dot(psi0, time=0.3) psi_block_2 = block_op.expm(psi0, H_time_eval=0.3, start=start, stop=stop, iterate=False, num=num, endpoint=True, block_diag=True) for psi_e_1, psi_b_1 in izip(psi_exact_1, psi_block_1): np.testing.assert_allclose(psi_b_1, psi_e_1, atol=1e-7) for psi_e_2, psi_b_2 in izip(psi_exact_2, psi_block_2): np.testing.assert_allclose(psi_b_2, psi_e_2, atol=1e-7) # imaginary time expH = exp_op(H, a=-1, start=start, stop=stop, iterate=True, num=num, endpoint=True) times = np.linspace(start, stop, num=num, endpoint=True) psi0 = np.random.ranf(H.Ns) psi0 /= np.linalg.norm(psi0) psi_exact_2 = expH.dot(psi0, time=0.3, shift=-E0) psi_block_2 = block_op.expm(psi0, a=-1, shift=-E0, H_time_eval=0.3, start=start, stop=stop, iterate=True, num=num, endpoint=True, block_diag=True) for psi_e_2, psi_b_2 in izip(psi_exact_2, psi_block_2): np.testing.assert_allclose(psi_b_2, psi_e_2, atol=1e-7) # same for iterate=False expH.set_iterate(False) psi_exact_2 = expH.dot(psi0, time=0.3, shift=-E0) psi_block_2 = block_op.expm(psi0, a=-1, shift=-E0, H_time_eval=0.3, start=start, stop=stop, iterate=False, num=num, endpoint=True, block_diag=True) for psi_e_2, psi_b_2 in izip(psi_exact_2, psi_block_2): np.testing.assert_allclose(psi_b_2, psi_e_2, atol=1e-7)
Expn2 = np.array([Obs2['Ozz_t'],Obs2['Ozz']]) psi_t2 = Obs2['psi_t'] Sent2 = Obs2['Sent_time']['Sent'] np.testing.assert_allclose(Expn,Expn2,atol=atol,rtol=rtol,err_msg='Failed observable comparison!') np.testing.assert_allclose(psi_t,psi_t2,atol=atol,rtol=rtol,err_msg='Failed state comparison!') np.testing.assert_allclose(Sent,Sent2,atol=atol,err_msg='Failed ent entropy comparison!') ### check obs_vs_time vs ED E,V = H2.eigh() psi_t=H2.evolve(psi0,0.0,t,iterate=False,rtol=solver_rtol,atol=solver_atol) psi_t4=exp_op(H2,a=-1j,start=0.0,stop=2.0,num=20,endpoint=True,iterate=True).dot(psi0) Obs = obs_vs_time(psi_t,t,Obs_list,return_state=True,Sent_args=Sent_args) Obs2 = obs_vs_time((psi0,E,V),t,Obs_list,return_state=True,Sent_args=Sent_args) Obs4 = obs_vs_time(psi_t4,t,Obs_list,return_state=True,Sent_args=Sent_args) psi_t3 = ED_state_vs_time(psi0,E,V,t,iterate=False) psi_t33 = np.asarray([psi for psi in ED_state_vs_time(psi0,E,V,t,iterate=True)]).T Expn = np.array([Obs['Ozz_t'],Obs['Ozz']]) psi_t = Obs['psi_t'] Sent = Obs['Sent_time']['Sent'] Expn2 = np.array([Obs2['Ozz_t'],Obs2['Ozz']])
err_msg='mixed: Failed ent entropy comparison!') ### check obs_vs_time vs ED E, V = H2.eigh() psi_t = H2.evolve(psi0, 0.0, t, iterate=False, rtol=solver_rtol, atol=solver_atol) psi_t4 = exp_op(H2, a=-1j, start=0.0, stop=2.0, num=20, endpoint=True, iterate=True).dot(psi0) Obs = obs_vs_time(psi_t, t, Obs_list, return_state=True, Sent_args=Sent_args) Obs2 = obs_vs_time((psi0, E, V), t, Obs_list, return_state=True, Sent_args=Sent_args) Obs4 = obs_vs_time(psi_t4,
Hx_1 = hamiltonian([["+",hx_1],["-",hx_1]],[],basis=basis_1,dtype=np.float64) # ###### calculate initial states ###### # calculating bandwidth for non-driven hamiltonian [E_12_min],psi_12 = Hzz_12.eigsh(k=1,which="SA") # [E_1_min],psi_1 = Hzz_1.eigsh(k=1,which="SA") # set up the initial states psi0_12 = psi_12.ravel() psi0_1 = psi_1.ravel() # ###### time evolution ###### # stroboscopic time vector nT = 200 # number of periods to evolve to t=Floquet_t_vec(Omega,nT,len_T=1) # t.vals=t, t.i=initial time, t.T=drive period # creating generators of time evolution using exp_op class U1_12 = exp_op(Hzz_12+A*Hx_12,a=-1j*t.T/4) U2_12 = exp_op(Hzz_12-A*Hx_12,a=-1j*t.T/2) U1_1 = exp_op(Hzz_1+A*Hx_1,a=-1j*t.T/4) U2_1 = exp_op(Hzz_1-A*Hx_1,a=-1j*t.T/2) # user-defined generator for stroboscopic dynamics def evolve_gen(psi0,nT,*U_list): yield psi0 for i in range(nT): # loop over number of periods for U in U_list: # loop over unitaries psi0 = U.dot(psi0) yield psi0 # get generator objects for time-evolved states psi_12_t = evolve_gen(psi0_12,nT,U2_12,U1_12,U2_12) psi_1_t = evolve_gen(psi0_1,nT,U2_1,U1_1,U2_1) # ###### compute expectation values of observables ######
x_field = [[g, i] for i in range(L)] z_field = [[h, i] for i in range(L)] J_nn = [[J, i, (i + 1) % L] for i in range(L)] # PBC # static and dynamic lists static = [["zz", J_nn], ["z", z_field], ["x", x_field]] dynamic = [] ###### construct Hamiltonian H = hamiltonian(static, dynamic, dtype=np.float64, basis=basis) # ###### compute evolution operator as matrix exponential start, stop, N_t = 0.0, 4.0, 21 # time vector parameters # define evolution operator U = exp_op(H, a=-1j, start=start, stop=stop, num=N_t, endpoint=True, iterate=True) print(U) # # compute domain wall initial state dw_str = "".join("1" for i in range(L // 2)) + "".join("0" for i in range(L - L // 2)) i_0 = basis.index(dw_str) # find index of product state in basis psi = np.zeros(basis.Ns) # allocate space for state psi[i_0] = 1.0 # set MB state to be the given product state # ##### calculate time-evolved state by successive application of matrix exponential psi_t = U.dot(
def exponentiate_at_hx(self, hx=0., a=-1j): return exp_op(self.hamiltonian_cont(time=hx), a=a)
Hzz_2d = hamiltonian([["zz", Jzz_2d]], [], basis=basis_2d, dtype=np.float64, **no_checks) Hx_2d = hamiltonian([["x", hx_2d]], [], basis=basis_2d, dtype=np.float64, **no_checks) # calculating bandwidth for non-driven hamiltonian [E_1d_min], psi_1d = Hzz_1d.eigsh(k=1, which="SA") [E_2d_min], psi_2d = Hzz_2d.eigsh(k=1, which="SA") # setting up initial states psi0_1d = psi_1d.ravel() psi0_2d = psi_2d.ravel() # creating generators of time evolution U1_1d = exp_op(Hzz_1d + omega * Hx_1d, a=-1j * T / 4) U2_1d = exp_op(Hzz_1d - omega * Hx_1d, a=-1j * T / 2) U1_2d = exp_op(Hzz_2d + omega * Hx_2d, a=-1j * T / 4) U2_2d = exp_op(Hzz_2d - omega * Hx_2d, a=-1j * T / 2) # get generator objects to get time dependent states psi_1d_t = evolve_gen(psi0_1d, nT, U1_1d, U2_1d, U1_1d) psi_2d_t = evolve_gen(psi0_2d, nT, U1_2d, U2_2d, U1_2d) # measure energy as a function of time Obs_1d_t = obs_vs_time(psi_1d_t, times, dict(E=Hzz_1d), return_state=True) Obs_2d_t = obs_vs_time(psi_2d_t, times, dict(E=Hzz_2d), return_state=True) # calculate page entropy density s_p_1d = np.log(2) - 2.0**(-L_1d // 2 - L_1d) / (2 * (L_1d // 2)) s_p_2d = np.log(2) - 2.0**(-N_2d // 2 - N_2d) / (2 * (N_2d // 2)) # calculating the entanglement entropy density Sent_time_1d = basis_1d.ent_entropy( Obs_1d_t["psi_t"], sub_sys_A=range(L_1d // 2))["Sent_A"] / (L_1d // 2)