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 test_ground_state_matches(self, dense, MPO_ham): h = MPO_ham(6) dmrg = DMRG1(h, bond_dims=8) dmrg.opts['eff_eig_dense'] = dense assert dmrg.solve() eff_e, mps_gs = dmrg.energy, dmrg.state mps_gs_dense = mps_gs.to_dense() assert_allclose(mps_gs_dense.H @ mps_gs_dense, 1.0) h_dense = h.to_dense() # check against dense form actual_e, gs = seigsys(h_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0) # check against actual MPO_ham if MPO_ham is MPO_ham_XY: ham_dense = ham_heis(6, cyclic=False, j=(1.0, 1.0, 0.0)) elif MPO_ham is MPO_ham_heis: ham_dense = ham_heis(6, cyclic=False) actual_e, gs = seigsys(ham_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0)
def test_ground_state_matches(self, dense, MPO_ham, cyclic): n = 10 tol = 3e-2 if cyclic else 1e-4 h = MPO_ham(n, cyclic=cyclic) dmrg = DMRG1(h, bond_dims=[4, 8, 12]) dmrg.opts['local_eig_ham_dense'] = dense dmrg.opts['periodic_segment_size'] = 1.0 dmrg.opts['periodic_nullspace_fudge_factor'] = 1e-6 assert dmrg.solve(tol=tol / 10, verbosity=1) assert dmrg.state.cyclic == cyclic eff_e, mps_gs = dmrg.energy, dmrg.state mps_gs_dense = mps_gs.to_dense() assert_allclose(mps_gs_dense.H @ mps_gs_dense, 1.0, rtol=tol) h_dense = h.to_dense() # check against dense form actual_e, gs = eigh(h_dense, k=1) assert_allclose(actual_e, eff_e, rtol=tol) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol) # check against actual MPO_ham if MPO_ham is MPO_ham_XY: ham_dense = ham_heis(n, cyclic=cyclic, j=(1.0, 1.0, 0.0), sparse=True) elif MPO_ham is MPO_ham_heis: ham_dense = ham_heis(n, cyclic=cyclic, sparse=True) actual_e, gs = eigh(ham_dense, k=1) assert_allclose(actual_e, eff_e, rtol=tol) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol)
def test_matches_exact(self, dense, MPO_ham): h = MPO_ham(6) dmrg = DMRG2(h, bond_dims=8) assert dmrg._k.site[0].dtype == float dmrg.opts['eff_eig_dense'] = dense assert dmrg.solve() # XXX: need to dispatch SLEPc seigsys on real input # assert dmrg._k.site[0].dtype == float eff_e, mps_gs = dmrg.energy, dmrg.state mps_gs_dense = mps_gs.to_dense() assert_allclose(mps_gs_dense.H @ mps_gs_dense, 1.0) h_dense = h.to_dense() # check against dense form actual_e, gs = seigsys(h_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0) # check against actual MPO_ham if MPO_ham is MPO_ham_XY: ham_dense = ham_heis(6, cyclic=False, j=(1.0, 1.0, 0.0)) elif MPO_ham is MPO_ham_heis: ham_dense = ham_heis(6, cyclic=False) actual_e, gs = seigsys(ham_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0)
def test_quevo_multi_compute(self, method, qtype): ham = ham_heis(2, cyclic=False) p0 = qu(up() & down(), qtype=qtype) def some_quantity(t, _): return t def some_other_quantity(_, pt): return logneg(pt) evo = QuEvo(p0, ham, method=method, compute={ 't': some_quantity, 'logneg': some_other_quantity }) manual_lns = [] for pt in evo.at_times(np.linspace(0, 1, 6)): manual_lns.append(logneg(pt)) ts = evo.results['t'] lns = evo.results['logneg'] 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_basic(self, sparse): ownership = (0, 7) hl = qu.Lazy(qu.ham_heis, n=4, sparse=sparse, shape=(16, 16)) print(hl) h = 1 * hl(ownership=ownership) h_ex = qu.ham_heis(n=4, sparse=sparse)[slice(*ownership), :] assert_allclose(h.A, h_ex.A)
def test_heisenberg(self, n, l, gap): ham = MPO_ham_heis(n) dmrg = DMRG2(ham) dmrg.solve() gl = gap // 2 gr = gap // 2 + gap % 2 m = n // 2 sysa = range(m - l - gl, m - gl) sysb = range(m + gr, m + l + gr) assert max(sysa) + gap + 1 == min(sysb) ln = dmrg.state.logneg_subsys(sysa, sysb, approx_spectral_opts={'bsz': 16}, verbosity=2) # exact lne = logneg_subsys(groundstate(ham_heis(n, cyclic=False)), [2] * n, sysa, sysb) assert_allclose(lne, ln, rtol=0.1, atol=0.1)
def main(): Hij = qu.ham_heis(2).astype(DTYPE) peps = qtn.PEPS.rand(LX, LY, bond_dim=2, dtype=DTYPE) hterms = {coos: Hij for coos in peps.gen_horizontal_bond_coos()} vterms = {coos: Hij for coos in peps.gen_vertical_bond_coos()} compute_expec_opts = dict(cutoff=0.0, max_bond=9, contract_optimize='random-greedy') optmzr = TNOptimizer( peps, loss_fn=state_energy, # norm_fn=normalize_state, loss_constants={ 'hterms': hterms, 'vterms': vterms }, loss_kwargs=compute_expec_opts, autodiff_backend=autodiff_backend, **autodiff_backend_opts) peps_opt = optmzr.optimize(10) return peps_opt
def test_progbar_update_to_integrate(self, capsys): ham = ham_heis(2, cyclic=False) p0 = up() & down() sim = QuEvo(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 = ham_heis(2, cyclic=False) p0 = up() & down() sim = QuEvo(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_quevo_at_times(self): ham = ham_heis(2, cyclic=False) p0 = up() & down() sim = QuEvo(p0, ham, method='solve') ts = np.linspace(0, 10) for t, pt in zip(ts, sim.at_times(ts)): x = cos(t) y = expec(pt, eyepad(pauli('z'), [2, 2], 0)) assert_allclose(x, y, atol=1e-15)
def test_progbar_at_times_solve(self, capsys): ham = qu.ham_heis(2, cyclic=False) p0 = qu.up() & qu.down() sim = qu.Evolution(p0, ham, method='solve', 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_mpo_site_ham_heis(self, cyclic, j, bz, n): hh_mpo = MPO_ham_heis(n, tags=['foo'], cyclic=cyclic, j=j, bz=bz) assert hh_mpo[0].tags == {'I0', 'foo'} assert hh_mpo[1].tags == {'I1', 'foo'} assert hh_mpo[-1].tags == {'I{}'.format(n - 1), 'foo'} assert hh_mpo.shape == (2, ) * 2 * n hh_ex = qu.ham_heis(n, cyclic=cyclic, j=j, b=bz) assert_allclose(qu.eigvalsh(hh_ex), qu.eigvalsh(hh_mpo.to_dense()), atol=1e-13)
def test_at_times(self, dt, tol): n = 10 psi0 = qtn.MPS_neel_state(n) H_int = qu.ham_heis(2, cyclic=False) tebd = qtn.TEBD(psi0, H_int, dt=dt, tol=tol) assert tebd.H.special_sites == set() for pt in tebd.at_times([0.1, 0.2, 0.3, 0.4, 0.5]): assert pt.H @ pt == approx(1, rel=1e-5) assert tebd.err <= 1e-5
def test_setup_and_sweep(self): n = 10 H_int = qu.ham_heis(n=2, cyclic=False) psi0 = qtn.MPS_neel_state(n, dtype=complex) tebd = qtn.TEBD(psi0, H_int, dt=0.05) assert tebd.pt.bond_size(0, 1) == 1 tebd.sweep('right', 1 / 2) assert tebd.pt.count_canonized() == (n - 1, 0) tebd.sweep('left', 1 / 2) assert tebd.pt.count_canonized() == (0, n - 1) assert tebd.pt.bond_size(0, 1) > 1 assert not tebd._queued_sweep
def test_mpo_site_ham_heis(self): hh_mpo = MPO_ham_heis(5, tags=['foo']) assert hh_mpo.site[0].tags == {'I0', 'foo'} assert hh_mpo.site[3].tags == {'I3', 'foo'} assert hh_mpo.site[-1].tags == {'I4', 'foo'} assert hh_mpo.shape == (2, ) * 10 hh_ = (hh_mpo ^ ...).fuse({ 'k': ['k0', 'k1', 'k2', 'k3', 'k4'], 'b': ['b0', 'b1', 'b2', 'b3', 'b4'] }) hh = ham_heis(5, cyclic=False) assert_allclose(hh, hh_.data)
def test_matches_exact(self, dense, MPO_ham, cyclic): n = 6 h = MPO_ham(n, cyclic=cyclic) tol = 3e-2 if cyclic else 1e-4 dmrg = DMRG2(h, bond_dims=[4, 8, 12]) assert dmrg._k[0].dtype == float dmrg.opts['local_eig_ham_dense'] = dense dmrg.opts['periodic_segment_size'] = 1.0 dmrg.opts['periodic_nullspace_fudge_factor'] = 1e-6 assert dmrg.solve(tol=tol / 10, verbosity=1) # XXX: need to dispatch SLEPc eigh on real input # assert dmrg._k[0].dtype == float eff_e, mps_gs = dmrg.energy, dmrg.state mps_gs_dense = mps_gs.to_dense() assert_allclose(expec(mps_gs_dense, mps_gs_dense), 1.0, rtol=tol) h_dense = h.to_dense() # check against dense form actual_e, gs = eigh(h_dense, k=1) assert_allclose(actual_e, eff_e, rtol=tol) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol) # check against actual MPO_ham if MPO_ham is MPO_ham_XY: ham_dense = ham_heis(n, cyclic=cyclic, j=(1.0, 1.0, 0.0)) elif MPO_ham is MPO_ham_heis: ham_dense = ham_heis(n, cyclic=cyclic) actual_e, gs = eigh(ham_dense, k=1) assert_allclose(actual_e, eff_e, rtol=tol) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol)
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_works(self, sz): prj = zspin_projector(4, sz) h = ham_heis(4) h0 = prj @ h @ prj.H v0s = eigvecs(h0) for v0 in v0s.T: vf = prj.H @ v0.T prjv = vf @ vf.H # Check reconstructed full eigenvectors commute with full ham assert_allclose(prjv @ h, h @ prjv, atol=1e-13) if sz == 0: # Groundstate must be in most symmetric subspace gs = groundstate(h) gs0 = prj .H @ v0s[:, 0] assert_allclose(expec(gs, gs0), 1.0) assert_allclose(expec(h, gs0), expec(h, gs))
def test_spin_half_double_space(self, sz): prj = qu.zspin_projector(5, sz) h = qu.ham_heis(5) h0 = prj.T @ h @ prj v0s = qu.eigvecsh(h0) for v0 in v0s.T: vf = prj @ v0.T prjv = vf @ vf.H # Check reconstructed full eigenvectors commute with full ham assert_allclose(prjv @ h, h @ prjv, atol=1e-13) if sz == 0: # Groundstate must be in most symmetric subspace gs = qu.groundstate(h) gs0 = prj @ v0s[:, 0] assert_allclose(qu.expec(gs, gs0), 1.0) assert_allclose(qu.expec(h, gs0), qu.expec(h, gs))
def test_works(self, sz): prj = qu.zspin_projector(4, sz) h = qu.ham_heis(4) h0 = prj.T @ h @ prj v0s = qu.eigvecsh(h0) for i in range(v0s.shape[1]): v0 = v0s[:, [i]] vf = prj @ v0 prjv = vf @ vf.H # Check reconstructed full eigenvectors commute with full ham assert_allclose(prjv @ h, h @ prjv, atol=1e-13) if sz == 0: # Groundstate must be in most symmetric subspace gs = qu.groundstate(h) gs0 = prj @ v0s[:, [0]] assert_allclose(qu.expec(gs, gs0), 1.0) assert_allclose(qu.expec(h, gs0), qu.expec(h, gs))
def heis_pbc(): L = 10 chi = 8 dtype = 'float32' psi0 = qtn.MPS_rand_state(L, chi, cyclic=True, seed=42).astype(dtype) H = qtn.MPO_ham_heis(L, cyclic=True).astype(dtype) def norm_fn(psi): factor = (psi & psi).contract(all, optimize='random-greedy') return psi / factor**0.5 def loss_fn(psi, H): k, H, b = qtn.align_TN_1D(psi, H, psi) energy = (k & H & b).contract(all, optimize='random-greedy') return energy en_ex = qu.groundenergy(qu.ham_heis(L, cyclic=True, sparse=True)) return psi0, H, norm_fn, loss_fn, en_ex
def test_quevo_compute_callback(self, qtype, method): ham = ham_heis(2, cyclic=False) p0 = qu(up() & down(), qtype=qtype) def some_quantity(t, pt): return t, logneg(pt) evo = QuEvo(p0, ham, method=method, compute=some_quantity) manual_lns = [] for pt in evo.at_times(np.linspace(0, 1, 6)): manual_lns.append(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
def test_ham_heis_2(self): h = qu.ham_heis(2, cyclic=False) evals = qu.eigvalsh(h) assert_allclose(evals, [-0.75, 0.25, 0.25, 0.25]) gs = qu.groundstate(h) assert_allclose(qu.expec(gs, qu.singlet()), 1.)
def test_ham_j1j2_3_dense(self): h = qu.ham_j1j2(3, j2=1.0, cyclic=False) h2 = qu.ham_heis(3, cyclic=True) assert_allclose(h, h2)
def test_sformat_construct(self, stype): h = qu.ham_heis(4, sparse=True, stype=stype) assert h.format == stype
def test_ham_heis_bz(self): h = qu.ham_heis(2, cyclic=False, b=1) evals = qu.eigvalsh(h) assert_allclose(evals, [-3 / 4, -3 / 4, 1 / 4, 5 / 4])
def test_ham_heis_sparse_cyclic_4(self, parallel): h = qu.ham_heis(4, sparse=True, cyclic=True, parallel=parallel) lk = qu.eigvalsh(h, k=4) assert_allclose(lk, [-2, -1, -1, -1])