def test_expm_slepc(self, expm_backend): ham = qu.ham_mbl(7, dh=0.5, sparse=True) psi = qu.rand_ket(2**7) evo_exact = qu.Evolution(psi, ham, method='solve') evo_slepc = qu.Evolution(psi, ham, method='expm', expm_backend=expm_backend) ts = np.linspace(0, 100, 6) for p1, p2 in zip(evo_exact.at_times(ts), evo_slepc.at_times(ts)): assert abs(qu.expec(p1, p2) - 1) < 1e-9
def solve(self) -> List[q.qarray]: dt = self.t_list[1] self.solved_states = [self.psi_0] self.solved_t_list = [0] latest_state = state = self.psi_0 latest_time = 0 # for i in tqdm(range(len(self.Omega))): for i in range(len(self.Omega)): Omega = self.Omega[i] Delta = self.Delta[i] self.evo = q.Evolution( latest_state, self.get_hamiltonian(Omega, Delta), # method="expm", method="integrate", # progbar=True, ) solve_points = np.linspace(0, dt, self.solve_points_per_timestep + 1)[1:] # Take away t=0 as a solve point for state in self.evo.at_times(solve_points): self.solved_states.append(state) self.solved_t_list += (solve_points + latest_time).tolist() latest_state = state latest_time = self.solved_t_list[-1] return self.solved_states
def test_evolve_obc(self, order, dt, tol): n = 10 tf = 2 psi0 = qtn.MPS_neel_state(n) H_int = qu.ham_heis(2, cyclic=False) if dt and tol: with pytest.raises(ValueError): qtn.TEBD(psi0, H_int, dt=dt, tol=tol) return tebd = qtn.TEBD(psi0, H_int, dt=dt, tol=tol) tebd.split_opts['cutoff'] = 0.0 if (dt is None and tol is None): with pytest.raises(ValueError): tebd.update_to(tf, order=order) return tebd.update_to(tf, order=order) assert tebd.t == approx(tf) assert not tebd._queued_sweep dpsi0 = psi0.to_dense() dham = qu.ham_heis(n=n, sparse=True, cyclic=False) evo = qu.Evolution(dpsi0, dham) evo.update_to(tf) assert qu.expec(evo.pt, tebd.pt.to_dense()) == approx(1, rel=1e-5)
def solve(e_qs: EvolvingQubitSystem) -> List[q.qarray]: dt = e_qs.t_list[1] e_qs.solved_states = [e_qs.psi_0] e_qs.solved_t_list = [0] latest_state = state = e_qs.psi_0 latest_time = 0 for i in tqdm(range(len(e_qs.Omega))): Omega = e_qs.Omega[i] Delta = e_qs.Delta[i] evo = q.Evolution( latest_state, get_hamiltonian_with_edge_fields(Omega, Delta), # method="expm", # progbar=True, ) solve_points = np.linspace(0, dt, e_qs.solve_points_per_timestep + 1)[1:] # Take away t=0 as a solve point for state in evo.at_times(solve_points): e_qs.solved_states.append(state) e_qs.solved_t_list += (solve_points + latest_time).tolist() latest_state = state latest_time = e_qs.solved_t_list[-1] return e_qs.solved_states
def test_evo_ham_dense_ket_solve(self, ham_rcr_psi, sparse, presolve): ham, trc, p0, tm, pm = ham_rcr_psi ham = qu.qu(ham, sparse=sparse) if presolve: l, v = qu.eigh(ham) sim = qu.Evolution(p0, (l, v)) assert isinstance(sim._ham, tuple) and len(sim._ham) == 2 else: sim = qu.Evolution(p0, ham, method='solve') sim.update_to(tm) assert_allclose(sim.pt, pm) assert qu.expec(sim.pt, p0) < 1.0 sim.update_to(trc) assert_allclose(sim.pt, p0) assert isinstance(sim.pt, qu.qarray) assert sim.t == trc
def test_ising_model_with_field(self, cyclic): p = qtn.MPS_computational_state('0000100000', cyclic=cyclic) pd = p.to_dense() H_nni = qtn.NNI_ham_ising(10, j=4, bx=1, cyclic=cyclic) H_mpo = qtn.MPO_ham_ising(10, j=4, bx=1, cyclic=cyclic) H = qu.ham_ising(10, jz=4, bx=1, cyclic=cyclic) tebd = qtn.TEBD(p, H_nni, tol=1e-6) tebd.split_opts['cutoff'] = 1e-9 tebd.split_opts['cutoff_mode'] = 'rel' evo = qu.Evolution(pd, H) e0 = qu.expec(pd, H) e0_mpo = qtn.expec_TN_1D(p.H, H_mpo, p) assert e0_mpo == pytest.approx(e0) tf = 2 ts = np.linspace(0, tf, 21) evo.update_to(tf) for pt in tebd.at_times(ts): assert isinstance(pt, qtn.MatrixProductState) assert (pt.H @ pt) == pytest.approx(1.0, rel=1e-5) assert (qu.expec(tebd.pt.to_dense(), evo.pt) == pytest.approx(1.0, rel=1e-5)) ef_mpo = qtn.expec_TN_1D(tebd.pt.H, H_mpo, tebd.pt) assert ef_mpo == pytest.approx(e0, 1e-5)
def test_progbar_update_to_integrate(self, capsys): ham = qu.ham_heis(2, cyclic=False) p0 = qu.up() & qu.down() sim = qu.Evolution(p0, ham, method='integrate', progbar=True) sim.update_to(100) # check something as been printed _, err = capsys.readouterr() assert err and "%" in err
def test_evo_at_times(self): ham = qu.ham_heis(2, cyclic=False) p0 = qu.up() & qu.down() sim = qu.Evolution(p0, ham, method='solve') ts = np.linspace(0, 10) for t, pt in zip(ts, sim.at_times(ts)): x = cos(t) y = qu.expec(pt, qu.ikron(qu.pauli('z'), [2, 2], 0)) assert_allclose(x, y, atol=1e-15)
def test_progbar_at_times_expm(self, capsys): ham = qu.ham_heis(2, cyclic=False) p0 = qu.up() & qu.down() sim = qu.Evolution(p0, ham, method='expm', progbar=True) for _ in sim.at_times(np.linspace(0, 100, 11)): pass # check something as been printed _, err = capsys.readouterr() assert err and "%" in err
def test_evo_ham(self, ham_rcr_psi, sparse, dop, method, timedep, linop): ham, trc, p0, tm, pm = ham_rcr_psi if dop: if method == 'expm': # XXX: not implemented return p0 = p0 @ p0.H pm = pm @ pm.H if method == 'bad': with raises(ValueError): qu.Evolution(p0, ham, method=method) return ham = qu.qu(ham, sparse=sparse) if linop: import scipy.sparse.linalg as spla ham = spla.aslinearoperator(ham) if timedep: # fake a time dependent ham by making it callable ham_object, ham = ham, (lambda t: ham_object) if linop and (method in ('expm', 'solve')): with raises(TypeError): qu.Evolution(p0, ham, method=method) return if timedep and (method in ('expm', 'solve')): with raises(TypeError): qu.Evolution(p0, ham, method=method) return sim = qu.Evolution(p0, ham, method=method) sim.update_to(tm) assert_allclose(sim.pt, pm, rtol=1e-4, atol=1e-6) assert qu.expec(sim.pt, p0) < 1.0 sim.update_to(trc) assert_allclose(sim.pt, p0, rtol=1e-4, atol=1e-6) assert isinstance(sim.pt, qu.qarray) assert sim.t == trc
def test_NNI_and_single_site_terms_heis(self): n = 10 psi0 = qtn.MPS_neel_state(n) H_nni = qtn.NNI_ham_heis(n, j=(0.7, 0.8, 0.9), bz=0.337) tebd = qtn.TEBD(psi0, H_nni) tebd.update_to(1.0, tol=1e-5) assert abs(psi0.H @ tebd.pt) < 1.0 assert tebd.pt.entropy(5) > 0.0 psi0_dns = qu.neel_state(n) H_dns = qu.ham_heis(10, j=(0.7, 0.8, 0.9), b=0.337, cyclic=False) evo = qu.Evolution(psi0_dns, H_dns) evo.update_to(1.0) assert qu.expec(tebd.pt.to_dense(), evo.pt) == pytest.approx(1.0)
def test_non_trans_invar(self): n = 10 tf = 1.0 p0 = qtn.MPS_rand_state(n, bond_dim=1) H = qtn.NNI_ham_mbl(n, dh=1.7, cyclic=False, seed=42) print(H) assert H.special_sites == {(i, i + 1) for i in range(n)} tebd = qtn.TEBD(p0, H) tebd.update_to(tf, tol=1e-3) p0d = p0.to_dense() Hd = qu.ham_mbl(n, dh=1.7, cyclic=False, seed=42, sparse=True) evo = qu.Evolution(p0d, Hd) evo.update_to(tf) assert qu.expec(tebd.pt.to_dense(), evo.pt) == pytest.approx(1.0)
def test_NNI_and_single_site_terms(self): n = 10 psi0 = qtn.MPS_neel_state(n) H_nni = qtn.NNI_ham_XY(n, bz=0.9) assert H_nni.special_sites == {(8, 9)} tebd = qtn.TEBD(psi0, H_nni) tebd.update_to(1.0, tol=1e-5) assert abs(psi0.H @ tebd.pt) < 1.0 assert tebd.pt.entropy(5) > 0.0 psi0_dns = qu.neel_state(n) H_dns = qu.ham_XY(10, jxy=1.0, bz=0.9, cyclic=False) evo = qu.Evolution(psi0_dns, H_dns) evo.update_to(1.0) assert qu.expec(tebd.pt.to_dense(), evo.pt) == pytest.approx(1.0)
def test_evo_compute_callback(self, qtype, method): ham = qu.ham_heis(2, cyclic=False) p0 = qu.qu(qu.up() & qu.down(), qtype=qtype) def some_quantity(t, pt): return t, qu.logneg(pt) evo = qu.Evolution(p0, ham, method=method, compute=some_quantity) manual_lns = [] for pt in evo.at_times(np.linspace(0, 1, 6)): manual_lns.append(qu.logneg(pt)) ts, lns = zip(*evo.results) assert len(lns) >= len(manual_lns) # check a specific value of logneg at t=0.8 was computed automatically checked = False for t, ln in zip(ts, lns): if abs(t - 0.8) < 1e-12: assert abs(ln - manual_lns[4]) < 1e-12 checked = True assert checked
def test_evo_multi_compute(self, method, qtype): ham = qu.ham_heis(2, cyclic=False) p0 = qu.qu(qu.up() & qu.down(), qtype=qtype) def some_quantity(t, _): return t def some_other_quantity(_, pt): return qu.logneg(pt) # check that hamiltonian gets accepted without error for all methods def some_other_quantity_accepting_ham(t, pt, H): return qu.logneg(pt) compute = { 't': some_quantity, 'logneg': some_other_quantity, 'logneg_ham': some_other_quantity_accepting_ham } evo = qu.Evolution(p0, ham, method=method, compute=compute) manual_lns = [] for pt in evo.at_times(np.linspace(0, 1, 6)): manual_lns.append(qu.logneg(pt)) ts = evo.results['t'] lns = evo.results['logneg'] lns_ham = evo.results['logneg_ham'] assert len(lns) >= len(manual_lns) # check a specific value of logneg at t=0.8 was computed automatically checked = False for t, ln, ln_ham in zip(ts, lns, lns_ham): if abs(t - 0.8) < 1e-12: assert abs(ln - manual_lns[4]) < 1e-12 # check that accepting hamiltonian didn't mess it up assert ln == ln_ham checked = True assert checked
J_evo1 = (0.0, 0.0, 0.0) H_evo1 = P.T @ qu.ham_mbl(N, W, J_evo1, cyclic=False, dh_dist='qp', beta=0.721, seed=seed, sparse=True).real @ P compute = { 'time': lambda t, p: t, 'losch': lambda t, p: qu.fidelity(Psi_ETH, p) } evo_ETH = qu.Evolution(Psi_ETH, H_evo1, compute=compute, method='expm') for t in evo_ETH.at_times(t_tab): continue TS = evo_ETH.results['time'] LOSCH_ETH = np.array(-np.log(evo_ETH.results['losch'])) / N ### MBL --> ETH ### W_i = params.W_i J_MBL = (0.0, 0.0, 0.0) H_MBL = P.T @ qu.ham_mbl(N, W_i, J_MBL,
def test_evo_timedep_adiabatic_with_callbacks(self, dop, linop, num_callbacks): # tests time dependent Evolution via an adiabatic sweep with: # a) no callbacks # b) 1 callback that accesses the time-dependent Hamiltonian # c) 2 callbacks where one access the Hamiltonian and one doesn't if num_callbacks > 0 and (dop or linop): # should implement this at some point return L = 6 T = 20 H1 = qu.ham_mbl(L, dh=1.0, seed=4, sparse=True) gs1 = qu.groundstate(H1) H2 = qu.ham_mbl(L, dh=1.0, seed=5, sparse=True) gs2 = qu.groundstate(H2) if linop: import scipy.sparse.linalg as spla H1 = spla.aslinearoperator(H1) H2 = spla.aslinearoperator(H2) # make sure two ground states are different assert qu.fidelity(gs1, gs2) < 0.5 # linearly interpolate from one ham to the other def ham(t): return (1 - t / T) * H1 + (t / T) * H2 if linop: assert isinstance(ham(0.3), spla.LinearOperator) if dop: p0 = qu.dop(gs1) else: p0 = gs1 if num_callbacks == 0: evo = qu.Evolution(p0, ham, progbar=True) else: def gs_overlap(t, pt, H): evals, evecs = eigs_scipy(H(t), k=1, which='SA') return np.abs(qu.dot(pt.T, qu.qu(evecs[:, 0])))**2 if num_callbacks == 1: compute = gs_overlap if num_callbacks == 2: def norm(t, pt): return qu.dot(pt.T, pt) compute = {'norm': norm, 'gs_overlap': gs_overlap} evo = qu.Evolution(p0, ham, compute=compute, progbar=True) evo.update_to(T) # final state should now overlap much more with second hamiltonian GS assert qu.fidelity(evo.pt, gs1) < 0.5 assert qu.fidelity(evo.pt, gs2) > 0.99 if num_callbacks == 1: gs_overlap_results = evo.results # check that we stayed in the ground state the whole time assert ((np.array(gs_overlap_results) - 1.0) < 1e-3).all() if num_callbacks == 2: norm_results = evo.results['norm'] gs_overlap_results = evo.results['gs_overlap'] # check that we stayed normalized the whole time assert ((np.array(norm_results) - 1.0) < 1e-3).all() # check that we stayed in the ground state the whole time assert ((np.array(gs_overlap_results) - 1.0) < 1e-3).all()
if dis_flag == 1: H_1 = qu.ham_mbl(N, W, J_tab, cyclic=False, dh_dist='qp', beta=0.721, seed=seed, sparse=True).real else: H_1 = qu.ham_mbl(N, W, J_tab, cyclic=False, seed=seed, sparse=True).real H_post = P.T @ H_1 @ P compute = {'time': lambda t, p: t, 'losch': lambda t, p: qu.fidelity(psi_0, p)} evo = qu.Evolution(psi_0, H_post, compute=compute, method='expm') for t in evo.at_times(t_tab): continue TS = evo.results['time'] LOSCH = np.array(-np.log(evo.results['losch'])) / N if dis_flag == 1: directory = '../DATA/GSQPWi' + str(W_i) + '/L' + str(N) + '/D' + str( W) + '/' PATH_now = LOCAL + os.sep + directory + os.sep if not os.path.exists(PATH_now): os.makedirs(PATH_now) else: directory = '../DATA/GSrandomWi' + str(W_i) + '/L' + str(N) + '/D' + str(
somma=0 for j in range(N//2): somma+=int(base[i][j]) ind_n[i]=[somma,i] StateList=[] for i in range(N//2+1): StateList.append(np.where(ind_n[:,0]==i)[0]) compute = { 'time': lambda t, p: t, 'losch': lambda t, p: np.square(np.absolute(qu.fidelity(psi_0, p))), 'imb': lambda t,p: np.real(I.expt_value(p)), 'entropy': lambda t, p: ent_entropy(p, basis, chain_subsys=subsys)['Sent_A'], 'num_ent': lambda t, p: hf.Num_ent(N, p, StateList) } evo = qu.Evolution(psi_0, H, compute=compute, method='solve') for pt in evo.at_times(t_tab): ts=evo.results['time'] Sent=N//2*(np.array(evo.results['entropy'])/np.log2(math.e)) P_N=np.array(evo.results['num_ent'])/np.log2(math.e) Losch=np.array(-np.log(evo.results['losch']))/N Imb=2*np.array(evo.results['imb']) if dis_flag == 1: directory = '../DATA/NeelQPLongJz'+str(int_flag)+'/L'+str(N)+'/D'+str(W)+'/' PATH_now = LOCAL+os.sep+directory+os.sep if not os.path.exists(PATH_now): os.makedirs(PATH_now)
def _get_evo(self): return q.Evolution(self.psi_0, self.get_hamiltonian())
# this makes the function print some information when called # - in order to be pickled is has to be located in the main package ham_heis_verbose = qu.utils.Verbosify(qu.ham_heis, highlight='ownership', mpi=True) H = qu.Lazy(ham_heis_verbose, n=n, sparse=True, shape=shape) # random initial state # - must make sure all processes have the same seed to be pure psi0 = qu.rand_ket(2**n, seed=42) # evolve the system, processes split 'hard' work (slepc computations) # - should see each worker gets given a different ownership rows # - but all end up with the results. evo = qu.Evolution(psi0, H, method='expm', expm_backend='slepc') evo.update_to(5) print(f"{rank}: I have final state norm {qu.expec(evo.pt, evo.pt)}") # Now lets demonstrate using the MPI pool construct pool = qu.get_mpi_pool() dims = [2] * n bsz = 5 logneg_subsys_verbose = qu.utils.Verbosify(qu.logneg_subsys, highlight='sysb', mpi=True) # each process only computes its own fraction of these # - should see each process calls logneg with different ``sysb``.